package com.zmn.oms.zmn.normal.business.impl.refund;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.base.common.data.common.dro.company.CompanyDRO;
import com.zmn.base.common.data.common.dro.tags.TagsDRO;
import com.zmn.base.common.data.dubbo.interfaces.company.CompanyListRemoteService;
import com.zmn.base.engineer.common.dro.foreign.engineer.ForeignEngineerDetailInfoDRO;
import com.zmn.base.engineer.common.enums.EngineerOAStatusEnum;
import com.zmn.base.engineer.dubbo.interfaces.foreign.EngineerListRemoteService;
import com.zmn.common.constant.FicoConsts;
import com.zmn.common.dto.pay.RefundResultDTO;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.dms.common.enums.DiscountTypeEnums;
import com.zmn.manager.redis.RedisManager;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.oms.business.interfaces.base.BaseCodeService;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.business.interfaces.messageV1.common.MessageSendBaseService;
import com.zmn.oms.business.interfaces.orderamount.OrderAmountBService;
import com.zmn.oms.business.interfaces.remark.OrderRemarkBService;
import com.zmn.oms.business.interfaces.work.OrderWorkAmountBService;
import com.zmn.oms.common.annotation.OrderWorkChangeSync;
import com.zmn.oms.common.annotation.ZsNormalOrderWorkLog;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dro.normal.master.ReworkRefundDRO;
import com.zmn.oms.common.dto.OmsOperator;
import com.zmn.oms.common.dto.OmsRefundRequestDTO;
import com.zmn.oms.common.dto.ResultDTO;
import com.zmn.oms.common.enums.RefundInitiateTypeEnum;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.utils.MobileUtil;
import com.zmn.oms.common.vo.KVDict;
import com.zmn.oms.model.bo.refund.RefundInitiateBO;
import com.zmn.oms.model.bo.work.review.RefundReviewBO;
import com.zmn.oms.model.dro.refund.RefundBacktrackingAmountDRO;
import com.zmn.oms.model.dto.finalprice.RefundDifferenceDTO;
import com.zmn.oms.model.dto.messageV1.AppMessageDTO;
import com.zmn.oms.model.dto.order.ConfirmDTO;
import com.zmn.oms.model.dto.order.zmn.ZsNormalRefundWorkDTO;
import com.zmn.oms.model.dto.remark.OrderRemarkDTO;
import com.zmn.oms.model.dto.remark.OrderRemarkDetailDTO;
import com.zmn.oms.model.dto.work.masterwork.CompleteDTO;
import com.zmn.oms.model.dto.work.refund.RefundApplyDTO;
import com.zmn.oms.model.dto.work.refund.RefundDTO;
import com.zmn.oms.model.dto.work.refund.WorkRefundResultDTO;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.master.OrderMaster;
import com.zmn.oms.model.entity.pay.OrderPay;
import com.zmn.oms.model.entity.refund.OrderWorkRefund;
import com.zmn.oms.model.entity.refund.OrderWorkRefundDetail;
import com.zmn.oms.model.entity.review.OmsOrderReview;
import com.zmn.oms.model.entity.warranty.OrderWarrantyProduct;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.vo.remark.OrderRemarkDetailVO;
import com.zmn.oms.model.vo.remark.OrderRemarkVO;
import com.zmn.oms.model.vo.work.OperatePermissionVO;
import com.zmn.oms.model.vo.work.refund.NoBacktrackingAmountVO;
import com.zmn.oms.model.vo.work.refund.RefundVO;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.master.OrderMasterService;
import com.zmn.oms.services.interfaces.masterworking.MasterWorkingService;
import com.zmn.oms.services.interfaces.orderpaydiscount.OrderPayDiscountService;
import com.zmn.oms.services.interfaces.pay.OrderPayService;
import com.zmn.oms.services.interfaces.refund.OrderWorkRefundDetailService;
import com.zmn.oms.services.interfaces.refund.OrderWorkRefundService;
import com.zmn.oms.services.interfaces.review.OmsOrderReviewService;
import com.zmn.oms.services.interfaces.warranty.OrderWarrantyProductService;
import com.zmn.oms.services.interfaces.warranty.OrderWarrantyService;
import com.zmn.oms.services.interfaces.work.OrderWorkAmountService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.order.ZsOrderBService;
import com.zmn.oms.zmn.business.interfaces.pay.OrderPayBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkOperatePermissionBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.oms.zmn.business.interfaces.work.orderpay.ZsOrderPayBService;
import com.zmn.oms.zmn.normal.business.interfaces.refund.RefundBService;
import com.zmn.oms.zmn.normal.business.interfaces.review.OmsOrderReviewBService;
import com.zmn.oms.zmn.normal.business.interfaces.work.ZsNormalWorkBService;
import com.zmn.oms.zmn.normal.business.interfaces.work.masterwork.ZsNormalMasterWorkBService;
import com.zmn.pay.common.constant.PayConsts;
import com.zmn.pay.common.dto.PayResultDTO;
import com.zmn.pay.gateway.common.model.dro.RefundResultDRO;
import com.zmn.tapi.dubbo.interfaces.dingtalk.DingTalkAuditService;
import com.zmn.vas.common.dro.order.card.times.OrderTimesCardDRO;
import com.zmn.vas.dubbo.interfaces.order.card.times.VasOrderTimesCardListRemoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.hbase.thirdparty.com.google.common.collect.Streams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：退款
 *
 * @author heciqi
 * @date 2019/08/09 16:55
 */
@Service
public class RefundBServiceImpl implements RefundBService {
	private Logger logger = LoggerFactory.getLogger(RefundBServiceImpl.class);


	@Autowired
	OrderWorkService orderWorkService;
	@Autowired
	OrderDetailService orderDetailService;
	@Autowired
	OrderWorkAmountService orderWorkAmountService;
	@Autowired
	OrderWorkAmountBService orderWorkBAmountBService;
	@Autowired
	OrderWorkRefundService orderWorkRefundService;
	@Autowired
	OrderRemarkBService orderRemarkBService;
	@Autowired
	ZsNormalWorkBService zsNormalWorkBService;
	@Autowired
	OrderDiscountService orderDiscountService;
	@Autowired
	OrderPayBService orderPayBService;
	@Autowired
	OrderPayService orderPayService;
	@Autowired
	ZsOrderPayBService zsOrderPayBService;
	@Autowired
	private OrderMasterService orderMasterService;
	@Autowired
	private OmsOrderReviewService orderReviewService;
	@Autowired
	private BaseCodeService baseCodeService;
	@Autowired
	private OmsOrderReviewBService orderReviewBService;
	@Autowired
	private ZsOrderWorkOperatePermissionBService orderWorkOperatePermissionBService;
	@Autowired
	MasterWorkingService masterWorkingService;
	@Autowired
	private OrderWorkRefundDetailService refundDetailService;
	@Autowired
	private ZsOrderBService zsOrderBService;
	@Autowired
	private MessageSendBaseService messageSendBaseService;
	@Autowired
	private ZsNormalMasterWorkBService zsNormalMasterWorkBService;
	@Autowired
	private WorkFlowContextBService workFlowContextBService;
	@Autowired
	private OrderAmountBService orderAmountBService;
	@Autowired
	private OrderWarrantyService orderWarrantyService;
	@Autowired
	private OrderWarrantyProductService orderWarrantyProductService;
	@Autowired
	private OrderPayDiscountService orderPayDiscountService;

	@Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
	CompanyListRemoteService companyListRemoteService;
	@Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
	EngineerListRemoteService engineerListRemoteService;
	@Reference(version = com.zmn.tapi.dubbo.DubboConsts.INTERFACE_VERSION, check = false)
	private DingTalkAuditService dingTalkAuditService;
	@Reference(version = com.zmn.vas.dubbo.consts.VasDubboConsts.INTERFACE_VERSION, check = false)
	private VasOrderTimesCardListRemoteService vasOrderTimesCardListRemoteService;

	@Resource
	private RedisManager redisManager;
	// 空跑单金额
	private static final int ONLY_RUN_ORDER_AMOUNT = 3000;

	@Resource
	private OrderLogBService orderLogBService;

	/**
	 * 申请退款
	 * @param refundApplyDTO
	 */
	@ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_APPLY_REFUND, beforeProceed = false)
	@Override
	public void applyRefund(RefundApplyDTO refundApplyDTO) throws OmsBaseException {

		// 退款验证
		OrderWork orderWork = orderWorkService.findOrderWorkByKey(refundApplyDTO.getOrderId(), refundApplyDTO.getWorkId());
		if (orderWork == null) {
			throw new OmsBaseException("订单不存在");
		}
		if (orderWork.getStatus() >= OrderStatusConsts.ORDER_STATUS_COMPLETE) {
			throw new OmsBaseException("完成后不申请退款");
		}
		if (Objects.equals(orderWork.getRefundReviewStatus(), OrderConsts.REVIEW_STATUS_DOING)) {
			throw new OmsBaseException("已申请了退款");
		}
		if (Objects.equals(orderWork.getRefundReviewStatus(), OrderConsts.REVIEW_STATUS_SUCCESS)) {
			throw new OmsBaseException("正在退款处理中");
		}
		if (Objects.nonNull(orderWork.getCancelTime())) {
			throw new OmsBaseException("取消后不能申请退款");
		}

		boolean unPrepayPay = !Objects.equals(PayConsts.PAY_STATUS_DONE, orderWork.getPrepayStatus()) || NumberUtil.isNullOrZero(orderWork.getPrepayAmount());
		boolean unDepositPay = !Objects.equals(PayConsts.PAY_STATUS_DONE, orderWork.getDepositStatus()) || NumberUtil.isNullOrZero(orderWork.getDepositAmount());
		if (unPrepayPay && unDepositPay) {// 无预付或无定金支付不能申请退款
			throw new OmsBaseException("无支付金额不能申请退款");
		}

		// 1，更新退款审核状态
		OrderWork upOrderWork = new OrderWork();
		upOrderWork.setOrderId(refundApplyDTO.getOrderId());
		upOrderWork.setWorkId(refundApplyDTO.getWorkId());
		upOrderWork.setRefundUserType(refundApplyDTO.getOperatorType());// 用户申请
		upOrderWork.setRefundReviewStatus(OrderConsts.REVIEW_STATUS_DOING);
		upOrderWork.setRefundApplyTime(refundApplyDTO.getApplyTime());
		orderWorkAmountService.updateRefund(upOrderWork);

		// 2，新增退款原因
		OrderRemarkDTO orderRemarkDTO = new OrderRemarkDTO();
		orderRemarkDTO.setOrderId(orderWork.getOrderId());
		orderRemarkDTO.setWorkId(orderWork.getWorkId());
		ArrayList<OrderRemarkDetailDTO> remarkList = Lists.newArrayList();
		Map<Integer, String> reasonMap = refundApplyDTO.getReasonMap();
		if (reasonMap != null) {
			orderRemarkDTO.setContent(reasonMap.get(GlobalConsts.NONE));
			reasonMap.remove(GlobalConsts.NONE);// 自定义原因
			reasonMap.forEach((k, v) ->{// 预定义原因
				OrderRemarkDetailDTO orderRemarkDetailDTO = new OrderRemarkDetailDTO();
				orderRemarkDetailDTO.setMapId(k);
				orderRemarkDetailDTO.setMapName(v);
				remarkList.add(orderRemarkDetailDTO);
			});
		}
		orderRemarkDTO.setDetailDTOList(remarkList);
		orderRemarkDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_USER);
		orderRemarkDTO.setOperatorId(orderWork.getUserId());
		orderRemarkBService.insertOrderRemark(orderRemarkDTO, OrderConsts.ORDER_REMARK_TYPE_REFUND);

		// 3. 更新MasterWorking.waitCancle状态
		masterWorkingService.updateMasterWorkingStatus(refundApplyDTO.getWorkId(), null, null, GlobalConsts.YES);
	}

	/**
	 * 提交退款
	 *
	 * @param refundDTO
	 */
	@Override
	@OrderWorkChangeSync
	@Transactional(rollbackFor = Exception.class)
	public OrderWork commitRefund(RefundDTO refundDTO) throws Exception {
		refundDTO.setOperateTime(DateUtil.getNow());
		String redisKey = String.format(RedisKeyConsts.ORDER_OPERATE_REFUND_KEY, String.valueOf(refundDTO.getOrderId()));
		if (redisManager.exists(redisKey)) {
			throw new OmsBaseException("当前时间24小时内，已建立一张退款单，不可重复退款");
		}

		OrderWork orderWork = Optional.ofNullable(refundDTO.getOrderWork()).orElse(orderWorkService.findOrderWorkByKey(refundDTO.getOrderId(), refundDTO.getWorkId()));
		// 如果是返修单查询原单信息
		if (Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REWORK)) {
			orderWork = orderWorkService.findOrderWorkByKey(orderWork.getOriginalId(), orderWork.getOriginalId());
			refundDTO.setOrderId(orderWork.getOrderId());
			refundDTO.setWorkId(orderWork.getWorkId());
			refundDTO.setRefundWorkId(orderWork.getOrderId());
		}

		if (!(Objects.equals(refundDTO.getResultStatus(), orderWork.getResultStatus()) && Objects.equals(refundDTO.getStatus(), orderWork.getStatus()))) {
			logger.debug("[{}]退款，订单状态变化", refundDTO.getWorkId());
			throw new OmsBaseException("订单状态发生变化，请刷新页面重新退款");
		}

		// 处理退款金额
		this.processRefundAmount(refundDTO, orderWork);

		// 需要审核 && 退款金额大于100元 && 不是现金退款 需要发起审批
		boolean isRefundReview = this.isNeedRefundReview(refundDTO);
		refundDTO.setRefundReview(isRefundReview);
		OrderWork refundOrderWork;
		try {
			// 完成后新建退款单
			logger.info("[{}]退款1，开始新建退款单", refundDTO.getWorkId());
			refundOrderWork = this.insertRefundOrderWork(refundDTO);

			// 生成refundDetail
			this.generateRefundDetail(refundDTO, refundOrderWork);

			// 有效期24小时
			redisManager.setex(redisKey, DateUtil.getNowFormatted(), 3600 * 24);

			// 工程师操作取公共配置
			if (Objects.equals(refundDTO.getOperatorType(), GlobalConsts.OPERATE_USER_TYPE_MASTER)) {
				// 取公共配置，是否自动确认
				TagsDRO baseCodeMapDRO = baseCodeService.getOneBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderRefundConsts.BASE_CODE_MAP_ONE_TYPE_OMS_REFUND_PROCESS, null);
				if (Objects.nonNull(baseCodeMapDRO) && Objects.equals(baseCodeMapDRO.getTwoTypeId(), GlobalConsts.YES)) {
					return refundOrderWork;
				}
			}

			// 自动确认
			ConfirmDTO confirmDTO = new ConfirmDTO();
			confirmDTO.setOrderId(refundOrderWork.getOrderId());
			confirmDTO.setWorkId(refundOrderWork.getWorkId());
			confirmDTO.setStatus(OrderStatusConsts.WORK_STATUS_CONFIRM);
			confirmDTO.setConfirmerId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
			confirmDTO.setConfirmTime(DateUtil.getNow());
			confirmDTO.setOperator("系统");
			confirmDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
			confirmDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
			zsOrderBService.confirmOrderSimple(confirmDTO);

			// 放到最后，以防退款消息过快
			if (NumberUtil.isNotNullOrZero(refundDTO.getDiscountRefundAmount())) {
				logger.info("[{}]退款-次卡退款", refundDTO.getWorkId());
				zsOrderPayBService.timesCardRefund(refundOrderWork, refundDTO);
			}
			if (!isRefundReview) {
				/*logger.info("[{}]发起审批", refundDTO.getWorkId());
				orderReviewBService.initiateRefundReview(refundOrderWork,refundDTO);
			} else {*/
				logger.info("[{}]退款2，调用退款支付", refundDTO.getWorkId());
				boolean cashRefund = Objects.equals(refundDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_OFFLINE)
						&& Objects.equals(refundDTO.getPayTargetChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_CASH);// 现金退款
				boolean isBackTracking = Objects.equals(refundDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE);// 原路返回
				// 现金退款和原路返回 & 不需要审核，调用退款支付
				if ((cashRefund || isBackTracking)) {
					logger.info("[{}]退款3，现金退款和原路返回，调用退款支付", refundDTO.getWorkId());
					List<OrderPay> orderPayList = orderPayBService.listOrderPayByOrderId(refundOrderWork.getOrderId());

					RefundInitiateBO refundInitiateBO = RefundInitiateBO.builder()
							.refundInitiateType(RefundInitiateTypeEnum.REFUND_ORDER.getType())
							.refundType(refundDTO.getRefundType())
							.refundAmount(refundDTO.getRefundAmount())
							.originalOrderId(orderWork.getOrderId())
							.originalOrderWorkBizType(orderWork.getBizType())
							.payTargetChannelId(refundDTO.getPayTargetChannelId())
							.payeeThirdAccount(refundDTO.getPayeeThirdAccount())
							.payeeThirdAccountName(refundDTO.getPayeeThirdAccountName())
							.payeeThirdAccountBank(refundDTO.getPayeeThirdAccountBank())
							.orderPayId(refundDTO.getOrderPayId())
							.refundOrderWork(refundOrderWork)
							.orderPayList(orderPayList)
							.operator(refundDTO)
							.build();

					zsOrderPayBService.payRefundAmount(refundInitiateBO);
				} else {
					// 插入待退款记录，待凭证保存，不掉用退款网关
					logger.info("[{}]退款3，插入待退款记录", refundOrderWork.getWorkId());
					orderPayBService.saveOfflineRefund(refundOrderWork.getOrderId(), refundOrderWork.getWorkId(), PayConsts.REFUND_STATUS_ING, refundDTO);
				}
			}
		} catch (OmsBaseException e) {
			refundFailHandle(orderWork, e.getMessage(),redisKey);
			throw e;
		} catch (Exception e){
			refundFailHandle(orderWork, "系统异常", redisKey);
			throw e;
		}
		return refundOrderWork;
	}

	/**
	 * 重复支付退款结果
	 * @param dto
	 */
	@Transactional(rollbackFor = Exception.class)
	@ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_DUPLICATE_PAY_REFUND_RESULT, beforeProceed = false)
	@Override
	public void duplicatePayRefund(com.zmn.oms.model.dto.order.pay.RefundResultDTO dto) {
		RefundResultDRO refundResultDRO = BeanMapper.map(dto, RefundResultDRO.class);
		dto.getRefundRequestDTO().setDuplicate(GlobalConsts.YES);
		orderPayBService.insertRefundOrderPay(refundResultDRO, dto.getRefundRequestDTO());
	}

	private void generateRefundDetail(RefundDTO refundDTO, OrderWork refundOrderWork) {
		OrderWorkRefundDetail orderWorkRefundDetail = new OrderWorkRefundDetail();
		orderWorkRefundDetail.setOrderId(refundOrderWork.getOrderId());
		orderWorkRefundDetail.setWorkId(refundOrderWork.getWorkId());
		orderWorkRefundDetail.setRefundType(refundDTO.getRefundType());
		orderWorkRefundDetail.setRefundPath(refundDTO.getPayTargetChannelId());
		orderWorkRefundDetail.setPayeeThirdAccount(refundDTO.getPayeeThirdAccount());
		orderWorkRefundDetail.setPayeeThirdAccountName(refundDTO.getPayeeThirdAccountName());
		orderWorkRefundDetail.setPayeeThirdAccountBank(refundDTO.getPayeeThirdAccountBank());
		refundDetailService.insertOrderWorkRefundDetail(orderWorkRefundDetail);
	}

	private void updateRefundDetail(RefundDTO refundDTO, OrderWork refundOrderWork,OrderWorkRefundDetail refundDetailDB) {
		OrderWorkRefundDetail orderWorkRefundDetail = new OrderWorkRefundDetail();
		orderWorkRefundDetail.setRefundDetailId(refundDetailDB.getRefundDetailId());
		orderWorkRefundDetail.setOrderId(refundOrderWork.getOrderId());
		orderWorkRefundDetail.setWorkId(refundOrderWork.getWorkId());
		orderWorkRefundDetail.setRefundType(refundDTO.getRefundType());
		orderWorkRefundDetail.setRefundPath(refundDTO.getPayTargetChannelId());
		orderWorkRefundDetail.setPayeeThirdAccount(refundDTO.getPayeeThirdAccount());
		orderWorkRefundDetail.setPayeeThirdAccountName(refundDTO.getPayeeThirdAccountName());
		orderWorkRefundDetail.setPayeeThirdAccountBank(refundDTO.getPayeeThirdAccountBank());
		refundDetailService.updateByDetailId(orderWorkRefundDetail);
	}


	/**
	 * 是否支持原路返回
	 * @param orderId
	 * @return
	 */
	@Override
	public boolean supportBacktracking(Long orderId) {
		// 过滤出支付记录
		List<OrderPay> orderPays = orderPayService.listOrderPayByOrderId(orderId)
				.stream()
				.filter(
						e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_INTIME)
								&& !Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_DISCOUNT)
				)
				.collect(Collectors.toList());
		return this.supportBacktracking(orderPays, orderId);
	}

	/**
	 * 分配退款资金
	 */
	@Override
	public List<OrderWorkRefund> distriRefundAmount(OrderWork orderWork, Integer refundAmount) throws OmsBaseException {
		boolean foundFailRefund = false;

		List<OrderWorkRefund> workRefund = orderWorkRefundService.findOrderWorkRefundByOrderIdAndWorkId(orderWork.getOrderId(), orderWork.getWorkId());
		if (!CollectionUtils.isEmpty(workRefund)) {
			boolean foundException = workRefund.stream().anyMatch(e -> Objects.equals(e.getRefundStatus(), GlobalConsts.REFUND_STATUS_EXCEPTION));
			if (foundException) {
				logger.error("[{}]退款异常订单", orderWork.getWorkId());
				throw new OmsBaseException("退款异常订单需要手动处理");
			}
			// 退款失败，删除失败的记录
			List<OrderWorkRefund> failRefunds = workRefund.stream().filter(e -> Objects.equals(e.getRefundStatus(), GlobalConsts.REFUND_STATUS_FAIL)).collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(failRefunds)) {
				foundFailRefund = true;
				for (OrderWorkRefund failRefund : failRefunds) {
					orderWorkRefundService.deleteOrderWorkRefund(failRefund.getOrderId(), failRefund.getRefundId());
				}
			}
		}

		List<OrderWorkRefund> list = Lists.newArrayList();
		// 退款单或失败的退款，用户现金退款
		if (Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REFUND) || foundFailRefund) {
			OrderWorkRefund orderWorkRefund = new OrderWorkRefund();
			orderWorkRefund.setOrderId(orderWork.getOrderId());
			orderWorkRefund.setWorkId(orderWork.getWorkId());
			orderWorkRefund.setAmount(refundAmount);
			orderWorkRefund.setAmountType(FicoConsts.ORDER_IN_MASTER);
			orderWorkRefund.setPayChannelId(PayConsts.PAY_CHANNEL_PLATFORM_OFFLINE);
			orderWorkRefund.setType(GlobalConsts.NO);
			orderWorkRefund.setRefundStatus(PayConsts.REFUND_STATUS_ING);
			orderWorkRefund.setCreater("sys");
			orderWorkRefund.setCreateTime(DateUtil.getNow());
			orderWorkRefundService.insertOrderWorkRefund(orderWorkRefund);
			list.add(orderWorkRefund);
			return list;
		}

		Integer canRefundAmount = refundAmount;
		// 工程师收款支付
		if (Objects.equals(orderWork.getMasterAmount(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(orderWork.getMasterAmount())) {
			// 计算剩余可退金额
			canRefundAmount = MathUtil.sub(refundAmount, orderWork.getMasterAmount());
			Integer masterRefundAmount = canRefundAmount >= 0 ? orderWork.getMasterAmount() : canRefundAmount;

			OrderWorkRefund orderWorkRefund = new OrderWorkRefund();
			orderWorkRefund.setOrderId(orderWork.getOrderId());
			orderWorkRefund.setWorkId(orderWork.getWorkId());
			orderWorkRefund.setAmount(masterRefundAmount);
			orderWorkRefund.setAmountType(FicoConsts.ORDER_IN_MASTER);
			orderWorkRefund.setPayChannelId(orderWork.getMasterPayChannelId());
			orderWorkRefund.setType(GlobalConsts.YES);
			orderWorkRefund.setRefundStatus(PayConsts.REFUND_STATUS_ING);
			orderWorkRefund.setCreater("sys");
			orderWorkRefund.setCreateTime(DateUtil.getNow());
			orderWorkRefundService.insertOrderWorkRefund(orderWorkRefund);
			list.add(orderWorkRefund);
		}
		if (canRefundAmount <= 0) {
			return list;
		}

		// 定金支付
		if (Objects.equals(orderWork.getDepositStatus(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(orderWork.getDepositAmount())) {
			// 计算剩余可退金额
			canRefundAmount = MathUtil.sub(canRefundAmount, orderWork.getDepositAmount());
			Integer depositRefundAmount = canRefundAmount >= 0 ? orderWork.getDepositAmount() : canRefundAmount;

			OrderWorkRefund orderWorkRefund = new OrderWorkRefund();
			orderWorkRefund.setOrderId(orderWork.getOrderId());
			orderWorkRefund.setWorkId(orderWork.getWorkId());
			orderWorkRefund.setAmount(depositRefundAmount);
			orderWorkRefund.setAmountType(FicoConsts.ORDER_IN_DEPOSIT);
			orderWorkRefund.setPayChannelId(orderWork.getDepositChannelId());
			orderWorkRefund.setType(GlobalConsts.YES);
			orderWorkRefund.setRefundStatus(PayConsts.REFUND_STATUS_ING);
			orderWorkRefund.setCreater("sys");
			orderWorkRefund.setCreateTime(DateUtil.getNow());
			orderWorkRefundService.insertOrderWorkRefund(orderWorkRefund);
			list.add(orderWorkRefund);
		}
		if (canRefundAmount <= 0) {
			return list;
		}

		// 啄木鸟预收退款
		if (Objects.equals(orderWork.getPrepayStatus(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(orderWork.getPrepayAmount())) {
			// 计算剩余可退金额
			canRefundAmount = MathUtil.sub(canRefundAmount, orderWork.getPrepayAmount());
			Integer prepayRefundAmount = canRefundAmount >= 0 ? orderWork.getPrepayAmount() : canRefundAmount;

			OrderWorkRefund orderWorkRefund = new OrderWorkRefund();
			orderWorkRefund.setOrderId(orderWork.getOrderId());
			orderWorkRefund.setWorkId(orderWork.getWorkId());
			orderWorkRefund.setAmount(prepayRefundAmount);
			orderWorkRefund.setAmountType(FicoConsts.ORDER_IN_PREPAY);
			orderWorkRefund.setPayChannelId(orderWork.getPrepayChannelId());
			orderWorkRefund.setType(GlobalConsts.YES);
			orderWorkRefund.setRefundStatus(PayConsts.REFUND_STATUS_ING);
			orderWorkRefund.setCreater("sys");
			orderWorkRefund.setCreateTime(DateUtil.getNow());
			orderWorkRefundService.insertOrderWorkRefund(orderWorkRefund);
			list.add(orderWorkRefund);
		}

		if (canRefundAmount <= 0) {
			return list;
		}

		OrderWorkRefund orderWorkRefund = new OrderWorkRefund();
		orderWorkRefund.setOrderId(orderWork.getOrderId());
		orderWorkRefund.setWorkId(orderWork.getWorkId());
		orderWorkRefund.setAmount(canRefundAmount);
		orderWorkRefund.setAmountType(FicoConsts.ORDER_IN_PREPAY);
		orderWorkRefund.setPayChannelId(PayConsts.PAY_CHANNEL_PLATFORM_OFFLINE);
		orderWorkRefund.setType(GlobalConsts.NO);
		orderWorkRefund.setRefundStatus(PayConsts.REFUND_STATUS_ING);
		orderWorkRefund.setCreater("sys");
		orderWorkRefund.setCreateTime(DateUtil.getNow());
		orderWorkRefundService.insertOrderWorkRefund(orderWorkRefund);
		list.add(orderWorkRefund);
		return list;
	}

	private OrderWork insertRefundOrderWork(RefundDTO refundDTO) throws Exception{
		ZsNormalRefundWorkDTO refundWorkDTO = new ZsNormalRefundWorkDTO();

		// 查询工程师信息
		// todo fubiao
		logger.info("insertRefundOrderWork#getEngineerDetailById 入参 [{}]",refundDTO.getMasterId());
		ResponseDTO<ForeignEngineerDetailInfoDRO> cacheEngineerByEngineerId = engineerListRemoteService.getEngineerDetailById(refundDTO.getMasterId());
		logger.info("insertRefundOrderWork#getEngineerDetailById 出参 [{}]",JSON.toJSONString(cacheEngineerByEngineerId));
		ForeignEngineerDetailInfoDRO baseEngineerDRO = cacheEngineerByEngineerId.getData();
		if (!cacheEngineerByEngineerId.isSuccess() || baseEngineerDRO == null) {
			throw new OmsBaseException("工程师信息不存在");
		}

		refundWorkDTO.setOrderId(refundDTO.getOrderId());
		refundWorkDTO.setWorkId(refundDTO.getWorkId());
		refundWorkDTO.setRefundWorkId(refundDTO.getRefundWorkId());
		refundWorkDTO.setMasterId(baseEngineerDRO.getEngineerId());
		refundWorkDTO.setMasterName(baseEngineerDRO.getRealName());
		refundWorkDTO.setRefundAmount(refundDTO.getRefundAmount());
		refundWorkDTO.setManageCompanyId(refundDTO.getCompanyId());
		refundWorkDTO.setManageCompanyName(refundDTO.getCompanyName());
		refundWorkDTO.setMasterList(refundDTO.getMasterList());
		refundWorkDTO.setRefundType(refundDTO.getRefundType());
		refundWorkDTO.setPayTargetChannelId(refundDTO.getPayTargetChannelId());
		refundWorkDTO.setPayeeThirdAccount(refundDTO.getPayeeThirdAccount());
		refundWorkDTO.setPayeeThirdAccountName(refundDTO.getPayeeThirdAccountName());
		refundWorkDTO.setPayeeThirdAccountBank(refundDTO.getPayeeThirdAccountBank());
		refundWorkDTO.setRefundReview(refundDTO.isRefundReview());
		refundWorkDTO.setRefundDTO(refundDTO);
		refundWorkDTO.setOperateTime(refundDTO.getOperateTime());

		// 退款缘由处理
		if (!CollectionUtils.isEmpty(refundDTO.getReasonList())) {
			List<Integer> reasonIdList = Lists.newArrayListWithCapacity(refundDTO.getReasonList().size());
			List<String> reasonNameList = Lists.newArrayListWithCapacity(refundDTO.getReasonList().size());
			refundDTO.getReasonList().forEach(item -> {
				reasonIdList.add(Integer.valueOf(item.getValue().toString()));
				reasonNameList.add(item.getText());
			});
			refundWorkDTO.setReasonIdList(reasonIdList);
			refundWorkDTO.setReasonNameList(reasonNameList);
		}

		// 设置管理公司类型
		ResponseDTO<CompanyDRO> manageCompany = companyListRemoteService.getCompanyDROById(refundDTO.getCompanyId());
		if (manageCompany.getData() != null) {
			refundWorkDTO.setManageCompanyType(manageCompany.getData().getChildType());
		}
		refundWorkDTO.setBizMode(refundDTO.getBizMode());
		refundWorkDTO.setOperatorRemark(refundDTO.getContent());
		refundWorkDTO.setOperatorId(refundDTO.getOperatorId());
		refundWorkDTO.setDeptId(refundDTO.getDeptId());
		refundWorkDTO.setOperator(refundDTO.getOperator());
		refundWorkDTO.setOperatorType(refundDTO.getOperatorType());
		refundWorkDTO.setPayStatus(PayConsts.REFUND_STATUS_ING);
		refundWorkDTO.setStatus(OrderStatusConsts.WORK_STATUS_INPUT);
		refundWorkDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
		refundWorkDTO.setOperatorLogRemark(String.format("退款单退款-退款缘由：%s；%s", StringUtils.join(Optional.ofNullable(refundWorkDTO.getReasonNameList()).orElse(Lists.newArrayList()), "；"), refundWorkDTO.getOperatorRemark()));
		refundDTO.setOperatorLogRemark(refundWorkDTO.getOperatorLogRemark());

		OrderWork refundOrderWork = zsNormalWorkBService.insertRefundOrderWork(refundWorkDTO);
		return refundOrderWork;
	}

	/**
	 * 修改退款结果
	 * @param refundResultDRO
	 */
	@Override
	public void updateRefundResult(RefundResultDRO refundResultDRO) {
		logger.info("修改退款结果===>{}", refundResultDRO);
		OmsRefundRequestDTO refundRequestDTO = JSON.parseObject(refundResultDRO.getRequestData(), OmsRefundRequestDTO.class);
		// 所有退款申请
		List<OrderWorkRefund> refundList = orderWorkRefundService.findOrderWorkRefundByOrderIdAndWorkId(refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId());

		// 1，更新退款表
		OrderWorkRefund orderWorkRefund = new OrderWorkRefund();
		orderWorkRefund.setRefundId(refundRequestDTO.getRefundId());
		orderWorkRefund.setOrderId(refundRequestDTO.getOrderId());
		orderWorkRefund.setWorkId(refundRequestDTO.getWorkId());
		orderWorkRefund.setOutTradeNo(refundResultDRO.getInnerTradeNo());
		orderWorkRefund.setOutRefundNo(refundResultDRO.getRefundOutTradeNo());
		orderWorkRefund.setRefundNo(refundResultDRO.getRefundInnerTradeNo());
		orderWorkRefund.setRefundStatus(refundResultDRO.getStatus());
		orderWorkRefund.setUpdater(refundRequestDTO.getOperator());
		orderWorkRefund.setUpdaterTime(new Date());
		orderWorkRefundService.updateByRefundId(orderWorkRefund);

		// 退款单更新支付明细表
		PayResultDTO payResultDTO = BeanMapper.map(orderWorkRefund,PayResultDTO.class);
		payResultDTO.setTradNo(orderWorkRefund.getRefundNo());
		payResultDTO.setOutTradNo(orderWorkRefund.getOutRefundNo());
		payResultDTO.setChannelId(refundResultDRO.getChannelId());
		payResultDTO.setPayType(orderWorkRefund.getType());
		payResultDTO.setPayStatus(orderWorkRefund.getRefundStatus());
		payResultDTO.setPayTime(refundResultDRO.getRefundTime());
		payResultDTO.setTradeType(GlobalConsts.PAY_TRADE_TYPE_REFUND);
		payResultDTO.setBizId(refundRequestDTO.getOrderId());
		payResultDTO.setAmountType(refundRequestDTO.getAmountType());
		payResultDTO.setAmount(refundResultDRO.getRefundAmount());
		payResultDTO.setRequestData(refundResultDRO.getRequestData());
		orderPayBService.insertOrderPay(payResultDTO);

		// 退款不成功，不作后续处理
		if (!Objects.equals(refundResultDRO.getStatus(), PayConsts.REFUND_STATUS_DONE)) {
			logger.info("[{}]退款不成功",refundRequestDTO.getWorkId());
			return;
		}

		// 2，更新工单退款状态
		Integer allRefund = GlobalConsts.NO;
		List<OrderWorkRefund> unRefundSuccessList = refundList.stream().filter(e -> !Objects.equals(e.getRefundStatus(), GlobalConsts.REFUND_STATUS_DONE)).collect(Collectors.toList());
		if (unRefundSuccessList.size() == 1 && unRefundSuccessList.stream().anyMatch(e -> Objects.equals(e.getRefundId(), refundRequestDTO.getRefundId()))) {
			logger.info("[{}]更新工单为已退款状态",refundRequestDTO.getWorkId());
			allRefund = GlobalConsts.YES;
		} else {
			logger.info("[{}]发现未全部退款，不作工单退款更新[{}]", refundRequestDTO.getWorkId(), unRefundSuccessList);
		}
		WorkRefundResultDTO workRefundResultDTO = BeanMapper.map(refundRequestDTO, WorkRefundResultDTO.class);
		workRefundResultDTO.setAllRefund(allRefund);

		RefundResultDTO refundResultDTO = BeanMapper.map(refundResultDRO,RefundResultDTO.class);
		refundResultDTO.setOutTradeNo(refundResultDRO.getInnerTradeNo());
		refundResultDTO.setOutRefundNo(refundResultDRO.getOutTradeNo());
		refundResultDTO.setRefundNo(refundResultDRO.getRefundOutTradeNo());
		refundResultDTO.setStatus(PayConsts.PAY_STATUS_DONE);
		refundResultDTO.setRefundAmount(refundResultDRO.getRefundAmount());
		refundResultDTO.setRefundTime(refundResultDRO.getRefundTime());
		workRefundResultDTO.setRefundResultDTO(refundResultDTO);
		workRefundResultDTO.setOperator(StringUtils.defaultString(refundRequestDTO.getOperator(),"1"));
		orderWorkBAmountBService.updateRefundResult(workRefundResultDTO);
	}


	/**
	 * 更新退款结果
	 * @param refundResultDRO
	 */
	@OrderWorkChangeSync
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateNewRefundResult(RefundResultDRO refundResultDRO) {
		logger.info("更新退款结果==>{}", refundResultDRO);
		OmsRefundRequestDTO refundRequestDTO = JSON.parseObject(refundResultDRO.getRequestData(), OmsRefundRequestDTO.class);
		String lockKey = String.format("%s_%s_%s", refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId(), PayConsts.PAY_TRADE_TYPE_REFUND);
		DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_REFUND_FORMAT + lockKey, LockConsts.LOCK_VALID_TIME);
		try {
			if (lock.tryLock()) {
				if (Objects.equals(refundRequestDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE)) {
					logger.info("更新退款结果，原路返回：{}", refundResultDRO);
					orderPayBService.insertRefundOrderPay(refundResultDRO, refundRequestDTO);
				} else {
					if (Objects.equals(PayConsts.PAY_CHANNEL_PLATFORM_CASH, refundRequestDTO.getPayTargetChannelId())) {
						logger.info("更新退款结果，线下现金退款：{}", refundResultDRO);
						RefundDTO refundDTO = new RefundDTO();
						refundDTO.setRefundType(refundRequestDTO.getRefundType());
						refundDTO.setPayTargetChannelId(refundRequestDTO.getPayTargetChannelId());
						refundDTO.setRefundAmount(refundResultDRO.getRefundAmount());
						orderPayBService.saveOfflineRefund(refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId(), refundResultDRO.getStatus(), refundDTO);
					} else {
						if (NumberUtil.isNotNullOrZero(refundRequestDTO.getOrderPayId())) {
							logger.info("更新退款结果，线下非现金退款：{}", refundResultDRO);
							OrderPay orderPay = new OrderPay();
							orderPay.setOrderPayId(refundRequestDTO.getOrderPayId());
							orderPay.setOrderId(refundRequestDTO.getOrderId());
							orderPay.setPayStatus(refundResultDRO.getStatus());
							orderPay.setPayTime(refundResultDRO.getRefundTime());
							orderPay.setUpdater(StringUtils.defaultString(refundRequestDTO.getOperator(),"系统"));
							orderPay.setUpdateTime(DateUtil.getNow());
							orderPayService.updateByPrimaryKeySelective(orderPay);
						} else {
							logger.info("更新退款结果，其他情况：{}", refundResultDRO);
							orderPayBService.insertRefundOrderPay(refundResultDRO, refundRequestDTO);
						}
					}
				}

				// 更新主表退款状态
				WorkRefundResultDTO workRefundResultDto = this.getWorkRefundResultDto(refundResultDRO);
				orderWorkBAmountBService.updateRefundResult(workRefundResultDto);

				// 退款单更新原单退款状态
				if (!Objects.equals(refundRequestDTO.getOrderId(),refundRequestDTO.getWorkId())) {
					logger.info("更新退款结果，退款单更新原单退款：{}", refundRequestDTO.getOrderId());
					List<OrderWork> orderWorks = orderWorkService.listEsOrderWorkByOrderIdList(Lists.newArrayList(refundRequestDTO.getOrderId()));


					// 排除赔偿单
					List<Long> compensateWorkIdList = orderWorks.stream()
							.filter(e -> Objects.equals(e.getType(), OrderConsts.ORDER_TYPE_COMPENSATE))
							.map(OrderWork::getWorkId)
							.collect(Collectors.toList());
					List<OrderPay> orderPays = orderPayService.listOrderPayByOrderId(refundRequestDTO.getOrderId());
					int sum = orderPays.stream()
							.filter(e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_REFUND))
							.filter(e -> Objects.equals(e.getPayStatus(), PayConsts.REFUND_STATUS_DONE))
							.filter(e -> !compensateWorkIdList.contains(e.getWorkId()))
							.mapToInt(OrderPay::getAmount)
							.sum();
					OrderWork upOrderWork = new OrderWork();
					upOrderWork.setOrderId(refundRequestDTO.getOrderId());
					upOrderWork.setWorkId(refundRequestDTO.getOrderId());
					upOrderWork.setPayStatus(refundResultDRO.getStatus());
					upOrderWork.setRefundTime(refundResultDRO.getRefundTime());
					upOrderWork.setRefundAmount(sum);
					upOrderWork.setRefundUserType(refundRequestDTO.getOperatorType());
					upOrderWork.setUpdater(refundRequestDTO.getOperator());
					orderWorkAmountService.updateRefund(upOrderWork);

					// 处理保修卡状态更新
					this.processOrderWarrantyCardStatusUpdate(refundRequestDTO, orderWorks, sum);

					// 处理返修单退款
					this.processReworkRefund(orderWorks, refundResultDRO, refundRequestDTO, workRefundResultDto);
				}
			}
		} catch (Exception e) {
			logger.error("订单退款异常:" + e.getMessage(), e);
		} finally {
			lock.unlock();
		}


		// 已完成 自动收单
//		if (Objects.equals(workRefundResultDto.getStatus(), OrderStatusConsts.WORK_STATUS_COMPLETE)) {
//			// 延迟1S进入自动流转，退款消息同样走异步，有延迟
//			workFlowContextBService.asyncAutoFlowDelay(workRefundResultDto.getOrderId(), workRefundResultDto.getWorkId(), 1);
//		}
	}

	/**
	 * 更新次卡订单退款结果
	 * @param refundResultDRO
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateTimesCardWorkRefundResult(RefundResultDRO refundResultDRO) {
		logger.info("更新次卡退款结果==>{}", refundResultDRO);
		OmsRefundRequestDTO refundRequestDTO = JSON.parseObject(refundResultDRO.getRequestData(), OmsRefundRequestDTO.class);

		String lockKey = String.format("%s_%s_%s", refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId(), PayConsts.PAY_TRADE_TYPE_REFUND);
		DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_REFUND_FORMAT + lockKey, LockConsts.LOCK_VALID_TIME);
		try {
			if (lock.tryLock()) {
			    // 处理次卡退款状态，均为线上原路返回
                refundRequestDTO.setRefundType(OrderConsts.ORDER_REFUND_TYPE_ONLINE);
                refundResultDRO.setRequestData(JSON.toJSONString(refundRequestDTO));

				// 更新主表退款状态
				WorkRefundResultDTO workRefundResultDto = this.getWorkRefundResultDto(refundResultDRO);
				orderWorkBAmountBService.updateRefundResult(workRefundResultDto);

				// 退完款才自动流转
				if (Objects.equals(workRefundResultDto.getAllRefund(), GlobalConsts.YES)
						&& workRefundResultDto.getWorkStatus() < OrderStatusConsts.WORK_STATUS_CHECKOUT) {
					// 自动流转
					workFlowContextBService.asyncAutoFlowDelay(refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId(), 5);
				}
			}
		} catch (Exception e) {
			logger.error("订单退款异常:" + e.getMessage(), e);
		} finally {
			lock.unlock();
		}

	}

	/**
	 * 处理返修单建退款单
	 * @param orderWorks
	 * @param refundResultDRO
	 * @param refundRequestDTO
	 * @param workRefundResultDto
	 */
	private void processReworkRefund(List<OrderWork> orderWorks, RefundResultDRO refundResultDRO,
									 OmsRefundRequestDTO refundRequestDTO, WorkRefundResultDTO workRefundResultDto) {
		try {
			OrderWork refund = Streams.findLast(orderWorks.stream()
					.filter(e -> Objects.equals(e.getWorkId(), refundRequestDTO.getWorkId()))).orElse(null);

			// 如果是返修单建的退款单，需要给源单工程师发送消息
			OrderWork refundWork = orderWorkService.findOrderWorkByKey(refund.getRefundWorkId(), refund.getRefundWorkId());
			if (Objects.equals(refundWork.getType(), OrderConsts.ORDER_TYPE_REWORK)) {
				// 退完款才完成返修单
				if (Objects.equals(workRefundResultDto.getAllRefund(), GlobalConsts.YES)) {
					// 更新完成
					CompleteDTO completeDTO = new CompleteDTO();
					completeDTO.setOrderId(refundWork.getOrderId());
					completeDTO.setWorkId(refundWork.getWorkId());
					completeDTO.setOperator("系统");
					completeDTO.setOperatorId(1L);
					completeDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
					completeDTO.setOperatorLogRemark("备注：返修未修好，工程师申请退款，自动完结返修单。");
					zsNormalMasterWorkBService.completeOrder(completeDTO);
					workFlowContextBService.asyncAutoFlowDelay(refundWork.getOrderId(), refundWork.getWorkId(), 5);
				}

				// 源单信息
				OrderWork original = Streams.findLast(orderWorks.stream()
						.filter(e -> Objects.equals(e.getType(), OrderConsts.ORDER_TYPE_NEW))).orElse(null);

				// 返修工程师不是源单工程师才发消息
				if (!Objects.equals(original.getMasterId(), refundWork.getMasterId())) {
					Map<String, Object> params = Maps.newHashMap();
					params.put("order_id", String.valueOf(original.getOrderId()));
					params.put("work_id", String.valueOf(original.getWorkId()));
					params.put("refund_amount", MoneyUtil.parseToYuanStr(refundResultDRO.getRefundAmount()));
					params.put("refund_type", refundRequestDTO.getRefundType() == OrderConsts.ORDER_REFUND_TYPE_ONLINE ? "原路退款" : "线下退款");

					AppMessageDTO appMessageDTO = new AppMessageDTO();
					appMessageDTO.setOrderId(original.getOrderId());
					appMessageDTO.setChannelId(String.valueOf(original.getChannelId()));
					appMessageDTO.setCityId(String.valueOf(original.getCityId()));
					appMessageDTO.setPlat(original.getPlatWork());
					appMessageDTO.setMasterId(original.getMasterId());
					appMessageDTO.setRuleId(MessageConsts.PUSH_MSG_RULE_ID_REWORK_REFUND);
					appMessageDTO.setParams(JSON.toJSONString(params));
					messageSendBaseService.sendAndroidAndIOSMessage(appMessageDTO);
				}
			}
			// 退完款才自动流转
			if (Objects.equals(workRefundResultDto.getAllRefund(), GlobalConsts.YES)) {
				// 自动流转
				workFlowContextBService.asyncAutoFlowDelay(refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId(), 5);
			}
		} catch (Exception e) {
			logger.error("[{}]返修单退款，退款成功后，自动完成异常", refundRequestDTO.getWorkId());
			logger.error(e.getMessage(), e);
		}
	}

	private WorkRefundResultDTO getWorkRefundResultDto(RefundResultDRO refundResultDRO){
		OmsRefundRequestDTO refundRequestDTO = JSON.parseObject(refundResultDRO.getRequestData(), OmsRefundRequestDTO.class);
		WorkRefundResultDTO workRefundResultDTO = BeanMapper.map(refundRequestDTO, WorkRefundResultDTO.class);
		RefundResultDTO refundResultDTO = BeanMapper.map(refundResultDRO,RefundResultDTO.class);
		refundResultDTO.setOutTradeNo(refundResultDRO.getInnerTradeNo());
		refundResultDTO.setOutRefundNo(refundResultDRO.getOutTradeNo());
		refundResultDTO.setRefundNo(refundResultDRO.getRefundOutTradeNo());
		refundResultDTO.setRefundAmount(refundResultDRO.getRefundAmount());
		refundResultDTO.setRefundTime(refundResultDRO.getRefundTime());
		workRefundResultDTO.setOperator(StringUtils.defaultString(refundRequestDTO.getOperator(),"系统"));

		OrderWork orderWork = orderWorkService.findOrderWorkByKey(refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId());

		workRefundResultDTO.setWorkStatus(orderWork.getStatus());

		if (Objects.equals(refundRequestDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE)) {
			// 判断是否全部退完
			List<OrderPay> orderPays = orderPayService.listOrderPayByOrderIdAndWorkIdsAndTradeTypeSrc(refundRequestDTO.getOrderId(), Lists.newArrayList(refundRequestDTO.getWorkId()), PayConsts.PAY_TRADE_TYPE_REFUND);
			int sum = orderPays.stream()
					.mapToInt(OrderPay::getAmount)
					.sum();
			if (Objects.equals(orderWork.getRefundAmount(),sum)) {
				workRefundResultDTO.setAllRefund(GlobalConsts.YES);
				// 退款状态
				long count = orderPays.stream()
						.filter(e -> Objects.equals(PayConsts.REFUND_STATUS_DONE, e.getPayStatus()))
						.count();
				if (count == orderPays.size()) {
					refundResultDTO.setStatus(PayConsts.REFUND_STATUS_DONE);
				}else {
					refundResultDTO.setStatus(PayConsts.REFUND_STATUS_FAIL);
				}
			} else {
				workRefundResultDTO.setAllRefund(GlobalConsts.NO);
			}
		}else {
			workRefundResultDTO.setAllRefund(GlobalConsts.YES);
			refundResultDTO.setStatus(refundResultDRO.getStatus());
		}
		workRefundResultDTO.setRefundResultDTO(refundResultDTO);
		// 退款单 全部退完&已退款状态 （已完成状态）
		if (Objects.equals(workRefundResultDTO.getAllRefund(), GlobalConsts.YES) &&
				Objects.equals(workRefundResultDTO.getRefundResultDTO().getStatus(), PayConsts.REFUND_STATUS_DONE) &&
				Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REFUND)
		) {
			workRefundResultDTO.setStatus(OrderStatusConsts.WORK_STATUS_COMPLETE);
		}
		return workRefundResultDTO;
	}

	@ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_REFUND_UPDATE, beforeProceed = false)
	@Transactional(rollbackFor = Exception.class)
	@Override
	public OrderWork updateRefund(RefundDTO refundDTO) throws OmsBaseException {
		refundDTO.setOperateTime(DateUtil.getNow());
		OrderWork refundOrderWork = orderWorkService.findOrderWorkByKey(refundDTO.getOrderId(), refundDTO.getWorkId());
		OmsOrderReview orderReview = orderReviewService.getOmsOrderReviewByOrderIdAndWorkIdAndType(refundDTO.getOrderId(), refundDTO.getWorkId(), OrderConsts.OMS_ORDER_REVIEW_REFUND);
		// 修改，终止审批
		orderReviewBService.stopReview(orderReview, refundDTO);

		// 上一次如果是 非原路退&不需要审批 则需要删除历史退款记录
		OrderPay refundPay = refundDTO.getHistoryOrderPay();
		//orderPayService.getOrderWorkRefundPay(refundOrderWork.getOrderId(), refundOrderWork.getWorkId());
		if (Objects.nonNull(refundPay)) {
			OrderPay orderPay = new OrderPay();
			orderPay.setOrderId(refundPay.getOrderId());
			orderPay.setOrderPayId(refundPay.getOrderPayId());
			orderPayService.deleteByKey(orderPay);
		}

		// 备注
		//OrderRemarkVO orderRemarkVO = orderRemarkBService.findOrderRemarkVO(refundDTO.getOrderId(), refundDTO.getWorkId(), OrderConsts.ORDER_REMARK_TYPE_REFUND);

		// set历史退款记录（日志使用）
		//refundDTO.setHistoryRemark(orderRemarkVO);
		//refundDTO.setHistoryOrderPay(refundPay);
		refundDTO.setHistoryRefundReview(orderReview);

		// 修改退款单金额
		OrderWork updateOrderWork = new OrderWork();
		updateOrderWork.setOrderId(refundOrderWork.getOrderId());
		updateOrderWork.setWorkId(refundOrderWork.getWorkId());
		updateOrderWork.setRefundAmount(refundDTO.getRefundAmount());
		updateOrderWork.setTotalAmount(Optional.ofNullable(refundDTO.getRefundAmount()).orElse(0) * -1);
		updateOrderWork.setOriginalAmount(Optional.ofNullable(refundDTO.getRefundAmount()).orElse(0) * -1);
		updateOrderWork.setUpdater(refundDTO.getOperator());
		updateOrderWork.setUpdateTime(DateUtil.getNow());
		orderWorkService.updateOrderWorkByKey(updateOrderWork);

		// 保存退款缘由
		OrderRemarkDTO orderRemarkDTO = new OrderRemarkDTO();
		orderRemarkDTO.setOrderId(refundDTO.getOrderId());
		orderRemarkDTO.setWorkId(refundOrderWork.getWorkId());
		orderRemarkDTO.setOperatorId(refundDTO.getOperatorId());
		orderRemarkDTO.setOperatorType(refundDTO.getOperatorType());
		orderRemarkDTO.setContent(refundDTO.getContent());

		// 退款原因选项
		if (Objects.nonNull(refundDTO.getReasonList())) {
			List<OrderRemarkDetailDTO> orderRemarkDetailList = Lists.newArrayListWithExpectedSize(refundDTO.getReasonList().size());
			for (KVDict kvDict : refundDTO.getReasonList()) {
				orderRemarkDetailList.add(new OrderRemarkDetailDTO(Integer.valueOf(kvDict.getValue().toString()), kvDict.getText(), null, 0));
			}
			orderRemarkDTO.setDetailDTOList(orderRemarkDetailList);
		}
		orderRemarkBService.insertOrderRemark(orderRemarkDTO, OrderConsts.ORDER_REMARK_TYPE_REFUND);

		// 需要审核 && 退款金额大于100元 && 不是现金退款 需要发起审批
		boolean isRefundReview = this.isNeedRefundReview(refundDTO);
		if (isRefundReview) {
			// 发起审批
			orderReviewBService.initiateRefundReview(refundOrderWork,refundDTO);
		} else {
			boolean cashRefund = Objects.equals(refundDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_OFFLINE)
					&& Objects.equals(refundDTO.getPayTargetChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_CASH);// 现金退款
			boolean isBackTracking = Objects.equals(refundDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE);// 原路返回
			// 现金退款和原路返回 & 不需要审核，调用退款支付
			if (cashRefund || isBackTracking) {
				logger.info("[{}]退款3，现金退款和原路返回，调用退款支付", refundDTO.getWorkId());
				OrderWork originalOrderWork = orderWorkService.findOrderWorkByKey(refundDTO.getOrderId(), refundDTO.getOrderId());
				List<OrderPay> orderPayList = orderPayBService.listOrderPayByOrderId(refundOrderWork.getOrderId());

				RefundInitiateBO refundInitiateBO = RefundInitiateBO.builder()
						.refundInitiateType(RefundInitiateTypeEnum.REFUND_ORDER.getType())
						.refundType(refundDTO.getRefundType())
						.refundAmount(refundDTO.getRefundAmount())
						.originalOrderId(originalOrderWork.getOrderId())
						.originalOrderWorkBizType(originalOrderWork.getBizType())
						.payTargetChannelId(refundDTO.getPayTargetChannelId())
						.payeeThirdAccount(refundDTO.getPayeeThirdAccount())
						.payeeThirdAccountName(refundDTO.getPayeeThirdAccountName())
						.payeeThirdAccountBank(refundDTO.getPayeeThirdAccountBank())
						.orderPayId(refundDTO.getOrderPayId())
						.refundOrderWork(refundOrderWork)
						.orderPayList(orderPayList)
						.operator(refundDTO)
						.build();

				zsOrderPayBService.payRefundAmount(refundInitiateBO);
			} else {
				logger.info("[{}]退款3，插入待退款记录", refundOrderWork.getWorkId());
				orderPayBService.saveOfflineRefund(refundOrderWork.getOrderId(), refundOrderWork.getWorkId(),
						PayConsts.REFUND_STATUS_ING, refundDTO);
			}
		}

		// 老数据原因可能会没有refundDetail
		OrderWorkRefundDetail refundDetail = refundDetailService.findOrderWorkRefundDetailByOrderIdAndWorkId(refundOrderWork.getOrderId(), refundOrderWork.getWorkId());
		if (Objects.isNull(refundDetail)) {
			this.generateRefundDetail(refundDTO, refundOrderWork);
		} else {
			this.updateRefundDetail(refundDTO, refundOrderWork, refundDetail);
		}
		return refundOrderWork;
	}

	/**
	 * 退款取消
	 * @param refundOrderWork
	 * @param omsOperator
	 */
	@Override
	public void refundOrderCancel(OrderWork refundOrderWork, OmsOperator omsOperator) throws OmsBaseException {
		OperatePermissionVO operatePermission = orderWorkOperatePermissionBService
				.getOperatePermission(refundOrderWork.getOrderId(), refundOrderWork.getWorkId(), OrderConsts.ORDER_OP_TYPE_CANCEL);
		if (!operatePermission.getCanOperate()) {
			throw new OmsBaseException(operatePermission.getMsg());
		}

		OmsOrderReview refundOrderReview = orderReviewService.getOmsOrderReviewByOrderIdAndWorkIdAndType(refundOrderWork.getOrderId(), refundOrderWork.getWorkId(), OrderConsts.OMS_ORDER_REVIEW_REFUND);
		orderReviewBService.stopReview(refundOrderReview, omsOperator);

		/**
		 * 终止成功后
		 * 2.修改退款单状态
		 * 3.修改退款记录状态
		 */
		Date now = DateUtil.getNow();
		OrderWork updateOrderWork = new OrderWork();
		updateOrderWork.setOrderId(refundOrderWork.getOrderId());
		updateOrderWork.setWorkId(refundOrderWork.getWorkId());
		updateOrderWork.setCancelTime(now);
		updateOrderWork.setCancelerId(omsOperator.getOperatorId());
		updateOrderWork.setCancelerType(omsOperator.getOperatorType());
		updateOrderWork.setResultTime(DateUtil.getNow());
		updateOrderWork.setResulterId(omsOperator.getOperatorId());
		updateOrderWork.setResulterType(omsOperator.getOperatorType());
		updateOrderWork.setResultStatus(OrderStatusConsts.WORK_RESULT_DISCARD);
		updateOrderWork.setPayStatus(PayConsts.REFUND_STATUS_EXCEPTION);
		orderWorkService.updateCancel(updateOrderWork);

		OrderPay refundPay = orderPayService.getOrderWorkRefundPay(refundOrderWork.getOrderId(), refundOrderWork.getWorkId());
		if (Objects.nonNull(refundPay)) {
			refundPay.setPayStatus(PayConsts.REFUND_STATUS_EXCEPTION);
			refundPay.setPayTime(now);
			refundPay.setUpdater(omsOperator.getOperator());
			refundPay.setUpdateTime(now);
			orderPayService.updateByPrimaryKeySelective(refundPay);
		}
	}



	@ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_REFUND_REVIEW, beforeProceed = false)
	@Override
	public void refundReviewComplete(RefundReviewBO refundReviewBO) throws OmsBaseException {
		OrderWork refundOrderWork = orderWorkService.findOrderWorkByKey(refundReviewBO.getOrderId(), refundReviewBO.getWorkId());

		if (Objects.equals(refundReviewBO.getReviewStatus(), OrderConsts.OMS_ORDER_REVIEW_STATUS_CHECK_SUCCESS)) {
			RefundDTO refundDTO = JSON.parseObject(refundReviewBO.getReviewData(), RefundDTO.class);
			boolean cashRefund = Objects.equals(refundDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_OFFLINE)
					&& Objects.equals(refundDTO.getPayTargetChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_CASH);// 现金退款
			boolean isBackTracking = Objects.equals(refundDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE);// 原路返回
			// 现金退款和原路返回，调用退款支付
			if (cashRefund || isBackTracking) {
				logger.info("[{}]退款3，现金退款和原路返回，调用退款支付", refundDTO.getWorkId());
				OrderWork originalOrderWork = orderWorkService.findOrderWorkByKey(refundDTO.getOrderId(), refundDTO.getOrderId());
				List<OrderPay> orderPayList = orderPayBService.listOrderPayByOrderId(refundOrderWork.getOrderId());

				RefundInitiateBO refundInitiateBO = RefundInitiateBO.builder()
						.refundInitiateType(RefundInitiateTypeEnum.REFUND_ORDER.getType())
						.refundType(refundDTO.getRefundType())
						.refundAmount(refundOrderWork.getRefundAmount())
						.originalOrderId(originalOrderWork.getOrderId())
						.originalOrderWorkBizType(originalOrderWork.getBizType())
						.orderPayId(refundDTO.getOrderPayId())
						.payTargetChannelId(refundDTO.getPayTargetChannelId())
						.payeeThirdAccount(refundDTO.getPayeeThirdAccount())
						.payeeThirdAccountName(refundDTO.getPayeeThirdAccountName())
						.payeeThirdAccountBank(refundDTO.getPayeeThirdAccountBank())
						.refundOrderWork(refundOrderWork)
						.orderPayList(orderPayList)
						.operator(refundDTO)
						.build();

				zsOrderPayBService.payRefundAmount(refundInitiateBO);
			}else {
				logger.info("[{}]退款3，插入待退款记录", refundOrderWork.getWorkId());
				orderPayBService.saveOfflineRefund(refundOrderWork.getOrderId(), refundOrderWork.getWorkId(),
						PayConsts.REFUND_STATUS_ING, refundDTO);
			}

		} else if (Objects.equals(refundReviewBO.getReviewStatus(), OrderConsts.OMS_ORDER_REVIEW_STATUS_CHECK_FAIL)){

			OrderWork updateOrderWork = new OrderWork();
			updateOrderWork.setOrderId(refundOrderWork.getOrderId());
			updateOrderWork.setWorkId(refundOrderWork.getWorkId());
			updateOrderWork.setResultTime(DateUtil.getNow());
			updateOrderWork.setResulterId(Long.valueOf(refundReviewBO.getReviewerId()));
			updateOrderWork.setResulterType(GlobalConsts.OPERATE_USER_TYPE_STAFF);
			updateOrderWork.setResultStatus(OrderStatusConsts.WORK_RESULT_DISCARD);
			updateOrderWork.setPayStatus(PayConsts.REFUND_STATUS_EXCEPTION);
			orderWorkService.updateCancel(updateOrderWork);
		}

		// 兼容处理退款详情数据
		OrderWorkRefundDetail refundDetail = refundDetailService.findOrderWorkRefundDetailByOrderIdAndWorkId(refundOrderWork.getOrderId(), refundOrderWork.getWorkId());
		if (Objects.nonNull(refundDetail)) {
			return;
		}

		RefundDTO refundDTO = JSON.parseObject(refundReviewBO.getReviewData(), RefundDTO.class);
		if (Objects.isNull(refundDTO)) {
			return;
		}

		if (Objects.isNull(refundDTO.getPayTargetChannelId())) {
			refundDTO.setPayTargetChannelId(GlobalConsts.NONE);
		}
		this.generateRefundDetail(refundDTO, refundOrderWork);
	}

	/**
	 * 获取返修退款配置
	 * @param orderId 原单
	 * @param workId 原单
	 * @return
	 */
	@Override
	public ReworkRefundDRO getReworkRefundConfig(Long orderId, Long workId) throws OmsBaseException {
		// 返修单
		OrderWork rework = orderWorkService.findOrderWorkByKey(orderId, workId);
		// 原单
		OrderWork original = orderWorkService.findOrderWorkByKey(rework.getOriginalId(), rework.getOriginalId());
		// 查询源单退款金额
		ReworkRefundDRO dro = new ReworkRefundDRO();
		dro.setSupportBacktracking(this.supportBacktracking(rework.getOriginalId()) ? GlobalConsts.YES : GlobalConsts.NO);
		// 已退次卡金额
		int onceCardRefundAmount = 0;
		if (NumberUtil.isNotNullOrZero(original.getDiscountPrepayAmount())) {
			List<OrderDiscount> orderDiscountList = orderDiscountService.listByOrderId(rework.getOriginalId()).stream()
					.filter(e -> Objects.equals(e.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType()))
					.collect(Collectors.toList());
			String itemCode = orderDiscountList.get(0).getItemCode();
			ResponseDTO<OrderTimesCardDRO> coupResponseDTO = vasOrderTimesCardListRemoteService.getOrderTimesCardByCouponCode(itemCode);
			logger.info("退款查询次卡信息 入参：{} 出参：{}", itemCode, JSON.toJSONString(coupResponseDTO));
			if (!coupResponseDTO.isSuccess()) {
				throw new OmsBaseException("无法获取订单优惠退款金额，请稍后重试");
			}
			onceCardRefundAmount = coupResponseDTO.getData().getRefundAmount();
		}
		dro.setMaxRefundAmount(original.getTotalAmount() - Optional.ofNullable(original.getRefundAmount()).orElse(0) - onceCardRefundAmount);
		// 计算标准退款金额
		this.calcStandardRefundAmount(rework, original, dro);
		// 支付方式
		List<KVDict> payChannelList = Lists.newArrayListWithCapacity(3);
		payChannelList.add(KVDict.builder().value(PayConsts.PAY_CHANNEL_PLATFORM_ALIPAY).text("支付宝").build());
		payChannelList.add(KVDict.builder().value(PayConsts.PAY_CHANNEL_PLATFORM_WEIXINPAY).text("微信").build());
		payChannelList.add(KVDict.builder().value(PayConsts.PAY_CHANNEL_PLATFORM_BANKTRANSFER).text("银行卡").build());
		dro.setPayChannelList(payChannelList);
		return dro;
	}

	/**
	 * 计算标准退款金额
	 * @param rework
	 * @param original
	 * @param dro
	 */
	private void calcStandardRefundAmount(OrderWork rework, OrderWork original, ReworkRefundDRO dro) {
		int maxRefundAmount = dro.getMaxRefundAmount() - 3000;
		if (maxRefundAmount <= 0) {
			return;
		}
		int diff = (int) DateUtil.getTimespan(original.getVisitTime(), rework.getVisitTime(), DateUtil.UNIT_DAY);
		switch (original.getCategOneId()) {
			// 空调
			case ProductConsts.CATEG_ONE_ID_AIR_CONDITIONER:
			// 冰箱
			case ProductConsts.CATEG_ONE_ID_FRIDGE:
			// 洗衣机
			case ProductConsts.CATEG_ONE_ID_WASHING_MACHINE:
			// 电视
			case ProductConsts.CATEG_ONE_ID_TELEVISION:
			// 热水器
			case ProductConsts.CATEG_ONE_ID_HEATER:
			// 燃气灶
			case ProductConsts.CATEG_ONE_ID_GAS_STOVE:
			// 油烟机
			case ProductConsts.CATEG_ONE_ID_RANGE_HOOD:
			// 饮水机
			case ProductConsts.CATEG_ONE_ID_WATER_DISPENSER:
			// 制冷设备
			case ProductConsts.CATEG_ONE_ID_REFRIGERATION_EQUIPMENT:
			// 厨房电器
			case ProductConsts.CATEG_ONE_ID_KITCHEN_APPLIANCE:
			// 生活电器
			case ProductConsts.CATEG_ONE_ID_LIFE_ELECTRIC:
			// 数码办公
			case ProductConsts.CATEG_ONE_ID_DIGITAL_OFFICE:
			// 装锁
			case ProductConsts.CATEG_ONE_ID_LOCK:
				// 规则1
				this.ruleOne(diff, dro, maxRefundAmount);
				break;
			// 管道
			case ProductConsts.CATEG_ONE_ID_RUSH_PIPE:
				// 规则2
				this.ruleTwo(diff, dro, maxRefundAmount);
				break;
			// 灯具电路
			case ProductConsts.CATEG_ONE_ID_LAMP_CIRCUIT:
			// 龙头管件
			case ProductConsts.CATEG_ONE_ID_FAUCET_FITTINGS:
			// 卫浴洁具
			case ProductConsts.CATEG_ONE_ID_TOILET_UTENSILS:
			// 五金挂件
			case ProductConsts.CATEG_ONE_ID_HARDWARE_ACCESSORIES:
			// 厨卫洁具
			case ProductConsts.CATEG_ONE_ID_KITCHEN_UTENSILS:
			// 开锁
			case ProductConsts.CATEG_ONE_ID_UNLOCK:
				// 规则3
				this.ruleThree(diff, dro, maxRefundAmount);
				break;
			// 换锁
			case ProductConsts.CATEG_ONE_ID_CHANGE_LOCK:
				break;
			// 家庭防水
			case ProductConsts.CATEG_ONE_ID_HOME_WATERPROOF:
			// 房屋翻新
			case ProductConsts.CATEG_ONE_ID_HOUSE_RENOVATION:
				// 规则4
				this.ruleFour(diff, dro, maxRefundAmount);
				break;
			default:
				break;
		}
	}

	/**
	 * 规则1
	 * 全款是最大退款金额
	 * <=1天 无
	 * <=7天 全款-30元
	 * <=30天 (全款-30元) * 0.7
	 * <=60天 (全款-30元) * 0.5
	 * <=90天 (全款-30元) * 0.3
	 * @param day 返修单源单上门日期与返修单上门日期的间隔天数
	 * @param dro
	 */
	private void ruleOne(int day, ReworkRefundDRO dro, int maxRefundAmount) {
		if (day <= 1) {
			return;
		} else if (day <= 7) {
			dro.setStandardRefundAmount(maxRefundAmount);
			dro.setStandardRefundDesc("标准退款金额 = 最大退款金额 - 30");
			dro.setReworkRefundDesc("维修7天内返修未修好");
		} else if (day <= 30) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.7")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.7");
			dro.setReworkRefundDesc("维修30天内返修未修好");
		} else if (day <= 60) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.5")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.5");
			dro.setReworkRefundDesc("维修60天内返修未修好");
		} else if (day <= 90) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.3")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.3");
			dro.setReworkRefundDesc("维修90天内返修未修好");
		}
	}

	/**
	 * 规则2
	 * 全款是最大退款金额
	 * <=1天 全款-30元
	 * @param day 返修单源单上门日期与返修单上门日期的间隔天数
	 * @param dro
	 */
	private void ruleTwo(int day, ReworkRefundDRO dro, int maxRefundAmount) {
		if (day <= 1) {
			dro.setStandardRefundAmount(maxRefundAmount);
			dro.setStandardRefundDesc("标准退款金额 = 最大退款金额 - 30");
			dro.setReworkRefundDesc("维修1天内返修未修好");
		}
	}

	/**
	 * 规则3
	 * 全款是最大退款金额
	 * <=1天 无
	 * <=7天 全款-30元
	 * <=30天 (全款-30元) * 0.7
	 * @param day 返修单源单上门日期与返修单上门日期的间隔天数
	 * @param dro
	 */
	private void ruleThree(int day, ReworkRefundDRO dro, int maxRefundAmount) {
		if (day <= 1) {
			return;
		} else if (day <= 7) {
			dro.setStandardRefundAmount(maxRefundAmount);
			dro.setStandardRefundDesc("标准退款金额 = 最大退款金额 - 30");
			dro.setReworkRefundDesc("维修7天内返修未修好");
		} else if (day <= 30) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.7")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.7");
			dro.setReworkRefundDesc("维修30天内返修未修好");
		}
	}

	/**
	 * 规则4
	 * 全款是最大退款金额
	 * <=1天 无
	 * <=7天 全款-30元
	 * <=30天 (全款-30元) * 0.9
	 * <=90天 (全款-30元) * 0.8
	 * <=180天 (全款-30元) * 0.7
	 * <=365天 (全款-30元) * 0.5
	 * @param day 返修单源单上门日期与返修单上门日期的间隔天数
	 * @param dro
	 */
	private void ruleFour(int day, ReworkRefundDRO dro, int maxRefundAmount) {
		if (day <= 1) {
			return;
		} else if (day <= 7) {
			dro.setStandardRefundAmount(maxRefundAmount);
			dro.setStandardRefundDesc("标准退款金额 = 最大退款金额 - 30");
			dro.setReworkRefundDesc("维修7天内返修未修好");
		} else if (day <= 30) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.9")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.9");
			dro.setReworkRefundDesc("维修30天内返修未修好");
		} else if (day <= 90) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.8")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.8");
			dro.setReworkRefundDesc("维修90天内返修未修好");
		} else if (day <= 180) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.7")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.7");
			dro.setReworkRefundDesc("维修180天内返修未修好");
		} else if (day <= 365) {
			dro.setStandardRefundAmount(com.zmn.oms.common.utils.MathUtil.amountMultiplyNumber(maxRefundAmount, new BigDecimal("0.5")));
			dro.setStandardRefundDesc("标准退款金额 = (最大退款金额 - 30) * 0.5");
			dro.setReworkRefundDesc("维修365天内返修未修好");
		}
	}

	/**
	 * 获取退款VO
	 * @param orderId
	 * @param workId
	 * @return
	 */
	@Override
	public RefundVO getRefundVO(Long orderId, Long workId, boolean isUpdate) throws OmsBaseException {

		OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);

		// 如果是返修单查询原单信息
		if (Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REWORK)) {
			orderWork = orderWorkService.findOrderWorkByKey(orderWork.getOriginalId(), orderWork.getOriginalId());
		}

		Integer discountPrepayAmount = orderWork.getDiscountPrepayAmount();

		// 支付记录
		List<OrderPay> orderPays = orderPayService.listOrderPayByOrderId(orderId);

		RefundVO refundVO = new RefundVO();
		refundVO.setRefundUserType(orderWork.getRefundUserType());
		refundVO.setStatus(orderWork.getStatus());
		refundVO.setResultStatus(orderWork.getResultStatus());
		refundVO.setPlatWork(orderWork.getPlatWork());

		// 修改退款单，预付使用原单的预付金额
		if (isUpdate) {
			OrderWork originalOrderWork = orderWorkService.findOrderWorkByKey(orderId, orderId);
			discountPrepayAmount = originalOrderWork.getDiscountPrepayAmount();
		}

		// 获取原路退信息
		RefundBacktrackingAmountDRO refundBacktrackingAmountDRO = this.getBackTracking(orderId, discountPrepayAmount, orderPays);
		refundVO.setSupportBacktracking(refundBacktrackingAmountDRO.isSupportBacktracking());

		if (refundBacktrackingAmountDRO.isSupportBacktracking()) {
			refundVO.setNoBacktrackingAmountVO(this.noBacktrackingAmount(orderPays));
			refundVO.setBacktrackingAmount(Optional.ofNullable(discountPrepayAmount).orElse(0) +
					Optional.ofNullable(refundBacktrackingAmountDRO.getBacktrackingAmount()).orElse(0));
		}

		// 仅有次卡支付 不支持人工退款
		refundVO.setSupportManualRefund(!Objects.equals(orderWork.getTotalAmount(), discountPrepayAmount));

		// 退款金额服务商
		List<KVDict<Integer>> serviceProviderList = this.getServiceProviderList(orderWork);
		refundVO.setCompanyList(serviceProviderList);
		// 退款工程师列表
		List<OrderMaster> masters = orderMasterService.listMasterByWorkId(orderWork.getOrderId(), orderWork.getWorkId());
		// 原单收入

		// 退款缘由
		List<TagsDRO> baseCodeMapDROS = baseCodeService.listBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderRefundConsts.BASE_CODE_MAP_ONE_TYPE_OMS_REFUND_REASON, null, null);
		List<KVDict<Integer>> refundReason = Lists.newArrayListWithCapacity(baseCodeMapDROS.size());
		if (CollectionUtil.isNotNullOrEmpty(baseCodeMapDROS)) {
			baseCodeMapDROS.forEach(e -> {
				// 如果是新增操作过滤三级id为空的
				if (!isUpdate && Objects.equals(e.getThreeTypeId(), GlobalConsts.NO)) {
					return;
				}
				refundReason.add(KVDict.<Integer>builder().value(e.getTagId()).text(e.getName()).build());
			});
			refundVO.setRefundReason(refundReason);
		}

		/*List<KVDict<Integer>> refundReason = baseCodeService.getBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderRefundConsts.BASE_CODE_MAP_ONE_TYPE_OMS_REFUND_REASON);
		// 新增退款单把工程师选择缘由去除
		if (!isUpdate) {
			refundReason = refundReason.stream().filter(e -> !e.getText().contains("仅工程师可选择")).collect(Collectors.toList());
		}
		refundVO.setRefundReason(refundReason);*/

		// 源单收入、已退金额
		Integer originalAmount = 0;
		Integer haveRefundAmount = 0;
		Integer haveBacktrackingAmount = 0;
		List<OrderWork> orderWorks = orderWorkService.listEsOrderWorkByOrderIdList(Lists.newArrayList(orderId));
		for (OrderWork work : orderWorks) {
			// 源单收入
			if (Objects.equals(orderId, work.getWorkId())) {
				originalAmount = work.getTotalAmount();
			}
			// 已退金额
			if (Objects.equals(work.getType(), OrderConsts.ORDER_TYPE_REFUND) && Objects.equals(work.getPayStatus(), PayConsts.REFUND_STATUS_DONE)) {
				haveRefundAmount += work.getRefundAmount();
			}
		}

		// 已原路退金额
		haveBacktrackingAmount = orderPays.stream()
				.filter(e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_REFUND))
				.filter(e -> Objects.equals(e.getPayStatus(), PayConsts.REFUND_STATUS_DONE))
				.filter(e -> Objects.equals(e.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE))
				.mapToInt(OrderPay::getAmount)
				.sum();

		// 合并已退次卡金额
		if (NumberUtil.isNotNullOrZero(orderWork.getDiscountPrepayAmount())) {
			int onceCardRefundAmount = orderWork.getDiscountPrepayAmount() - refundBacktrackingAmountDRO.getOnceCardAmount();
			haveRefundAmount += onceCardRefundAmount;
			haveBacktrackingAmount += onceCardRefundAmount;
		}
		refundVO.setOriginalAmount(originalAmount);
		refundVO.setHaveRefundAmount(Math.abs(haveRefundAmount));
		refundVO.setHaveBacktrackingAmount(Math.abs(haveBacktrackingAmount));

		Set<Integer> masterIdList = masters.stream().map(OrderMaster::getMasterId).collect(Collectors.toSet());
		//ResponseDTO<List<BaseEngineerDRO>> mastersResponseDTO = engineerListRemoteService.listEngineerByEngineerIdList(masterIdList, orderWork.getPlatWork());
		//todo fubiao
		logger.info("getRefundVO#listEngineerDetailByIdSet 入参 [{}]",JSON.toJSONString(masterIdList));
		ResponseDTO<List<ForeignEngineerDetailInfoDRO>> mastersResponseDTO = engineerListRemoteService.listEngineerDetailByIdSet(masterIdList);
		logger.info("getRefundVO#listEngineerDetailByIdSet 出参 [{}]",JSON.toJSONString(mastersResponseDTO));
		Map<Integer, ForeignEngineerDetailInfoDRO> masterMap = mastersResponseDTO.getData().stream().collect(Collectors.toMap(ForeignEngineerDetailInfoDRO::getEngineerId, baseEngineerDRO -> baseEngineerDRO));

		List<KVDict<Integer>> masterList = masters.stream().map(e -> {
			StringBuilder sb = new StringBuilder();
			sb.append(e.getMasterName()).append("-");
			sb.append(MobileUtil.formatHideTel(e.getMasterPhone())).append("-");
			if (masterMap.containsKey(e.getMasterId())) {
				ForeignEngineerDetailInfoDRO baseEngineerDRO = masterMap.get(e.getMasterId());
				// todo EngineerDict.getEngineerStatusName(baseEngineerDRO.getStatus()
				sb.append(EngineerOAStatusEnum.getEnumByCode(baseEngineerDRO.getOaStatus()).getName());
			}
			return KVDict.<Integer>builder().value(e.getMasterId()).text(sb.toString()).type(e.getType()).build();
		}).collect(Collectors.toList());
		refundVO.setMasterList(masterList);
		refundVO.setPlatWork(orderWork.getPlatWork());
		refundVO.setStatus(orderWork.getStatus());
		refundVO.setResultStatus(orderWork.getResultStatus());

		// 退款单修改页面参数
		if (Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REFUND)) {
			refundVO.setRefundAmount(Math.abs(orderWork.getRefundAmount()));
			// 退款缘由
			OrderRemarkVO orderRemarkVO = orderRemarkBService.findOrderRemarkVO(orderId, workId, OrderConsts.ORDER_REMARK_TYPE_REFUND);
			refundVO.setContent(orderRemarkVO != null ? orderRemarkVO.getContent() : null);
			if (Objects.nonNull(orderRemarkVO) && CollectionUtil.isNotNullOrEmpty(orderRemarkVO.getDetailVOList())) {
				Set<Integer> selectedMapIds = orderRemarkVO.getDetailVOList()
						.stream()
						.map(OrderRemarkDetailVO::getMapId)
						.collect(Collectors.toSet());
				for (KVDict<Integer> reason : refundReason) {
					if (selectedMapIds.contains(reason.getValue())) {
						reason.setSelected(true);
					}
				}
			}
			// 如果退款记录和审核记录都没有的话是不允许进入修改页面
			// 退款信息
			List<OrderPay> orderRefundPays = orderPayService.listOrderPayByOrderIdAndWorkIdsAndTradeType(orderId, Lists.newArrayList(workId), PayConsts.PAY_TRADE_TYPE_REFUND);
			if (CollectionUtil.isNotNullOrEmpty(orderRefundPays)) {
				OrderPay orderPay = orderRefundPays.get(0);
				refundVO.setRefundType(orderPay.getRefundType());
				refundVO.setPayTargetChannelId(orderPay.getPayTargetChannelId());
				refundVO.setPayeeThirdAccount(orderPay.getPayeeThirdAccount());
				refundVO.setPayeeThirdAccountBank(orderPay.getPayeeThirdAccountBank());
				refundVO.setPayeeThirdAccountName(orderPay.getPayeeThirdAccountName());
				if (Objects.equals(orderPay.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE)) {
					refundVO.setRefundTypeText("原路退款");
				}else {
					switch (orderPay.getPayTargetChannelId()) {
						case PayConsts.PAY_CHANNEL_PLATFORM_ALIPAY:
							refundVO.setRefundTypeText("支付宝");
							break;
						case PayConsts.PAY_CHANNEL_PLATFORM_WEIXINPAY:
							refundVO.setRefundTypeText("微信");
							break;
						case PayConsts.PAY_CHANNEL_PLATFORM_BANKTRANSFER:
							refundVO.setRefundTypeText("银行卡");
							break;
						case PayConsts.PAY_CHANNEL_PLATFORM_CASH:
							refundVO.setRefundTypeText("现金退款");
							break;
					}
				}
			}else {
				OmsOrderReview orderReview = orderReviewService.getOmsOrderReviewByOrderIdAndWorkIdAndType(orderId, workId, OrderConsts.OMS_ORDER_REVIEW_REFUND);
				if (!Objects.isNull(orderReview) && StringUtil.isNotBlank(orderReview.getReviewData())) {
					RefundDTO refundOrderReviewDTO = JSON.parseObject(orderReview.getReviewData(), RefundDTO.class);
					refundVO.setRefundType(refundOrderReviewDTO.getRefundType());
					refundVO.setPayTargetChannelId(refundOrderReviewDTO.getPayTargetChannelId());
					refundVO.setPayeeThirdAccount(refundOrderReviewDTO.getPayeeThirdAccount());
					refundVO.setPayeeThirdAccountBank(refundOrderReviewDTO.getPayeeThirdAccountBank());
					refundVO.setPayeeThirdAccountName(refundOrderReviewDTO.getPayeeThirdAccountName());
					if (Objects.equals(refundOrderReviewDTO.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_ONLINE)) {
						refundVO.setRefundTypeText("原路退款");
					}else {
						switch (refundOrderReviewDTO.getPayTargetChannelId()) {
							case PayConsts.PAY_CHANNEL_PLATFORM_ALIPAY:
								refundVO.setRefundTypeText("支付宝");
								break;
							case PayConsts.PAY_CHANNEL_PLATFORM_WEIXINPAY:
								refundVO.setRefundTypeText("微信");
								break;
							case PayConsts.PAY_CHANNEL_PLATFORM_BANKTRANSFER:
								refundVO.setRefundTypeText("银行卡");
								break;
							case PayConsts.PAY_CHANNEL_PLATFORM_CASH:
								refundVO.setRefundTypeText("现金退款");
								break;
						}
					}
				}
			}
		}

		logger.debug("退款页面初始化模型[{}]", refundVO);
		return refundVO;
	}

	/**
	 * 获取原路退信息
	 *
	 * @param orderId              原单号
	 * @param discountPrepayAmount 次卡金额
	 * @param orderPays            原单支付记录
	 * @return
	 * @throws OmsBaseException
	 */
	@Override
	public RefundBacktrackingAmountDRO getBackTracking(Long orderId, Integer discountPrepayAmount, List<OrderPay> orderPays) throws OmsBaseException {

		// 可原路退支付列表
		List<OrderPay> canRefundOrderPays = orderPays.stream()
				.filter(e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_INTIME)
						&& !Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_DISCOUNT))
				.collect(Collectors.toList());

		// 次卡原路退
		List<OrderDiscount> orderDiscountList = orderDiscountService.listByOrderId(orderId).stream()
				.filter(e -> Objects.equals(e.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType()))
				.collect(Collectors.toList());

		// 可退次卡金额
		int onceCardAmount = 0;
		if (CollectionUtil.isNotNullOrEmpty(orderDiscountList)) {
			if (Objects.isNull(discountPrepayAmount)) {
				throw new OmsBaseException("有次卡优惠无次卡金额，请稍后重试");
			}
			String itemCode = orderDiscountList.get(0).getItemCode();
			ResponseDTO<OrderTimesCardDRO> coupResponseDTO = vasOrderTimesCardListRemoteService.getOrderTimesCardByCouponCode(itemCode);
			logger.info("退款查询次卡信息 入参：{} 出参：{}", itemCode, JSON.toJSONString(coupResponseDTO));
			if (!coupResponseDTO.isSuccess()) {
				throw new OmsBaseException("无法获取订单优惠退款金额，请稍后重试");
			}

			onceCardAmount = discountPrepayAmount - coupResponseDTO.getData().getRefundAmount();
			if (CollectionUtil.isNullOrEmpty(canRefundOrderPays)) {
				return RefundBacktrackingAmountDRO.builder()
						.supportBacktracking(true)
						.onceCardAmount(onceCardAmount)
						.backtrackingAmount(0)
						.build();
			}
		}

		// 存在人工退款不支持原路退 (人工退款需要次卡金额) 备注：人工退会使用原路退金额
		boolean hasOrderRefundTypeOffline = orderPays.stream().anyMatch(e ->
				Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_REFUND) &&
						Objects.equals(e.getPayStatus(), PayConsts.REFUND_STATUS_DONE) &&
						Objects.equals(e.getRefundType(), OrderConsts.ORDER_REFUND_TYPE_OFFLINE));
		if (hasOrderRefundTypeOffline) {
			return RefundBacktrackingAmountDRO.builder()
					.onceCardAmount(onceCardAmount)
					.supportBacktracking(false)
					.build();
		}

		// 人工退款需要次卡
		if (CollectionUtil.isNullOrEmpty(canRefundOrderPays)) {
			return RefundBacktrackingAmountDRO.builder()
					.onceCardAmount(onceCardAmount)
					.supportBacktracking(false)
					.build();
		}

		// 厂商的授信和余额支付可以原路返回
		List<OrderPay> pays = orderPays.stream()
				.filter(e -> Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_BALANCEAMOUNT)
						|| Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_CREDIT))
				.collect(Collectors.toList());
		if (CollectionUtil.isNotNullOrEmpty(pays)) {
			int backtrackingAmount = pays.stream().mapToInt(OrderPay::getAmount).sum();// 可退金额
			List<String> innerTradeNos = pays.stream().map(OrderPay::getInnerTradeNo).collect(Collectors.toList());// 可退金额支付流水号
			return RefundBacktrackingAmountDRO.builder()
					.onceCardAmount(onceCardAmount)
					.backtrackingAmount(backtrackingAmount)
					.innerTradeNoList(innerTradeNos)
					.supportBacktracking(true)
					.build();
		}

		// 计算可原路退金额 (预付款+模版支付)
		List<OrderPay> collect = canRefundOrderPays.stream()
				.filter(e -> Objects.equals(e.getPayStatus(), PayConsts.PAY_STATUS_DONE))
				.filter(e -> Objects.equals(e.getAmountType(), OrderPayConsts.ORDER_PAY_PREPAY)
						|| OrderPayConsts.TEMPLATE_PAY_TYPE_LIST.contains(e.getPayType()))
				.collect(Collectors.toList());
		if (CollectionUtil.isNullOrEmpty(collect)) {
			return RefundBacktrackingAmountDRO.builder()
					.onceCardAmount(onceCardAmount)
					.supportBacktracking(false)
					.build();
		}

		int backtrackingAmount = collect.stream().mapToInt(OrderPay::getAmount).sum();// 可退金额
		List<String> innerTradeNos = collect.stream().map(OrderPay::getInnerTradeNo).collect(Collectors.toList());// 可退金额支付流水号
		return RefundBacktrackingAmountDRO.builder()
				.supportBacktracking(true)
				.onceCardAmount(onceCardAmount)
				.backtrackingAmount(backtrackingAmount)
				.innerTradeNoList(innerTradeNos)
				.build();
	}

	/**
	 * 服务商列表
	 * @param orderWork
	 * @return
	 */
	private List<KVDict<Integer>> getServiceProviderList(OrderWork orderWork) {

		List<KVDict<Integer>> companyList = Lists.newArrayList();
		// 判断原服务商是否满足条件
		companyList.add(KVDict.<Integer>builder().value(orderWork.getManageCompanyId()).text(orderWork.getManageCompanyName()).selected(true).build());
		return companyList;
	}

	/**
	 * 是否需要审核
	 *
	 * 需要审核 && 退款金额大于100元 && 不是现金退款 需要发起审批
	 * @param refundDTO
	 * @return
	 */
	private boolean isNeedRefundReview(RefundDTO refundDTO){
		return refundDTO.isReview() && refundDTO.getRefundAmount() > 10000 && !Objects.equals(refundDTO.getPayTargetChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_CASH);
	}

	// /**
	//  * 队列写入工单凭证
	//  *
	//  * @param orderWork
	//  * @param refundResultDTO
	//  */
	// private void sendRefundOrderVoucherQueue(OrderWork orderWork, OmsRefundRequestDTO refundRequestDTO, RefundResultDRO refundResultDRO) {
	//  VoucherOrderDTO voucherOrderDTO = new VoucherOrderDTO();
	//  voucherOrderDTO.setPlat(refundResultDTO.getPlat());
	//  voucherOrderDTO.setCompanyId(orderWork.getCompanyId());
	//  voucherOrderDTO.setCompanyName(orderWork.getCompanyName());
	//  voucherOrderDTO.setOrgTwoId(orderWork.getOrgTwoId());
	//  voucherOrderDTO.setOrgThreeId(orderWork.getOrgThreeId());
	//  voucherOrderDTO.setOrgFourId(orderWork.getOrgFourId());
	//  voucherOrderDTO.setCityId(orderWork.getCityId());
	//  voucherOrderDTO.setNaturalCityId(orderWork.getNaturalCityId());
	//  voucherOrderDTO.setOrderId(orderWork.getOrderId());
	//  voucherOrderDTO.setWorkId(orderWork.getWorkId());
	//  voucherOrderDTO.setAmountType(refundRequestDTO.getAmountType());
	//  voucherOrderDTO.setCash(refundRequestDTO.getCash() == null ? GlobalConsts.NO : refundRequestDTO.getCash());
	//  voucherOrderDTO.setRefundResultDTO(refundResultDTO);
	//
	//  OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(orderWork.getOrderId());
	//  voucherOrderDTO.setCityName(orderDetail.getCityName());
	//  voucherOrderDTO.setProductInfo(orderDetail.getProductInfo());
	//  voucherOrderDTO.setServCategId(orderWork.getServCategId());
	//  voucherOrderDTO.setServCategName(orderDetail.getServCategName());
	//
	//  logger.info("[{}]工单退款凭证发送队列[{}]", orderWork.getWorkId(), voucherOrderDTO);
	//  String json = JSON.toJSONString(voucherOrderDTO);
	//  String key = String.valueOf(orderWork.getWorkId());
	//  zmnMQSender.send(MqTopicConsts.ZMN_TOPIC_FICO, MqTagConsts.ZMN_TOPIC_FICO_VOCHER_ORDER_TAG, key, json);
	// }

	private void processRefundAmount(RefundDTO refundDTO, OrderWork originalOrderWork) throws OmsBaseException {
        // 次卡订单 先退次卡金额，后退订单支付金额
		// 退款单总计退款金额
		Integer refundAmount = refundDTO.getRefundAmount();

		// 退了次卡之后还剩多少需要退
		Integer lastAmountNeedRefund = refundDTO.getRefundAmount();
		// 需要从优惠中退的金额
		Integer discountRefundAmount = null;

		// 重复支付
		if (Objects.nonNull(originalOrderWork) && NumberUtil.isNotNullOrZero(originalOrderWork.getDiscountPrepayAmount())) {
			// 查询已退多少金额
			// 已退金额
			Integer haveRefundAmount = 0;
			// 原单次卡金额
			Integer discountPrepayAmount = originalOrderWork.getDiscountPrepayAmount();
			List<OrderWork> orderWorks = orderWorkService.listEsOrderWorkByOrderIdList(Lists.newArrayList(originalOrderWork.getOrderId()));
			for (OrderWork work : orderWorks) {
				if (Objects.equals(work.getType(), OrderConsts.ORDER_TYPE_REFUND) && Objects.equals(work.getPayStatus(), PayConsts.REFUND_STATUS_DONE)) {
					haveRefundAmount += work.getRefundAmount();
				}
			}
			// 查询次卡已退金额
			if (NumberUtil.isNotNullOrZero(originalOrderWork.getDiscountPrepayAmount())) {
				List<OrderDiscount> discountList = orderDiscountService.listByOrderId(originalOrderWork.getOrderId());
				Optional<OrderDiscount> discountOptional = discountList.stream().filter(e -> Objects.equals(e.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType())).findFirst();
				if (discountOptional.isPresent()) {
					ResponseDTO<OrderTimesCardDRO> coupResponseDTO = vasOrderTimesCardListRemoteService.getOrderTimesCardByCouponCode(discountOptional.get().getItemCode());
					logger.info("退款查询次卡信息 入参：{} 出参：{}", discountOptional.get().getItemCode(), JSON.toJSONString(coupResponseDTO));
					if (!coupResponseDTO.isSuccess()) {
						throw new OmsBaseException("无法获取订单优惠退款金额，请稍后重试");
					}
					OrderTimesCardDRO dro = coupResponseDTO.getData();
					haveRefundAmount += Optional.ofNullable(dro.getRefundAmount()).orElse(0);
				}
			}


			if (haveRefundAmount < discountPrepayAmount) {
				// 两种情况 1已退 + 本次退款 <= 优惠预付金额 全部由次卡退款
				if (haveRefundAmount + lastAmountNeedRefund <= discountPrepayAmount) {
					discountRefundAmount = lastAmountNeedRefund;
					lastAmountNeedRefund = 0;
				} else {
					// 2已退 + 本次退款 > 优惠预付金额 次卡退部分
					discountRefundAmount = discountPrepayAmount - haveRefundAmount;
					lastAmountNeedRefund = lastAmountNeedRefund - discountRefundAmount;
				}
			}

		}

		// 订单需要退款的金额
		refundDTO.setRefundAmount(lastAmountNeedRefund);
		// 次卡需要退款的金额
		refundDTO.setDiscountRefundAmount(discountRefundAmount);
		// 退款单的退款金额
		refundDTO.setOrderRefundAmount(refundAmount);
	}

	/**
	 * 是否支持原路返回(app)
	 *
	 * @param orderPays
	 * @param orderId
	 * @return
	 */
	private boolean supportBacktracking(List<OrderPay> orderPays, Long orderId) {
		// 过滤次卡优惠券, 有次卡优惠券，允许原路退款 358739031019859968
		List<OrderDiscount> orderDiscountList = orderDiscountService.listByOrderId(orderId)
				.stream()
				.filter(e -> Objects.equals(e.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType()))
				.collect(Collectors.toList());
		//TODO 临时处理 次卡支付支持原路退款，暂无支付记录
		if (CollectionUtil.isNotNullOrEmpty(orderDiscountList) && CollectionUtil.isNullOrEmpty(orderPays)) {
			return true;
		}
		if (CollectionUtil.isNullOrEmpty(orderPays)) {
			return false;
		}

		// 厂商的授信和余额支付可以原路返回
		boolean isFactoryPay = orderPays.stream()
				.allMatch(e -> Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_BALANCEAMOUNT)
						|| Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_CREDIT));

		if (isFactoryPay) {
			return true;
		}

		// 必须全是线上支付才能原路返回
		boolean isAllOnlinePay = orderPays.stream()
				.filter(e -> !Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_DISCOUNT))
				.allMatch(e -> PayConsts.REAL_PAY_CHANNEL.contains(e.getPayChannelId()));
		if (!isAllOnlinePay) {
			return false;
		}

		// 存在app支付（可能为工程师支付），不能原路返回
		boolean isMasterPay = orderPays.stream()
				.anyMatch(e -> Objects.equals(e.getPayType(), PayConsts.PAY_TYPE_APP)
				);
		return !isMasterPay;
	}


	/**
	 * 处理保修卡状态更新
	 * 	 判断是否符合修改保修卡条件 1、金额退款是否全退 2、剩余金额是否低于30元/3000分 3、是否存在符合条件的保修卡
	 * @param refundRequestDTO 退款结果对象
	 * @param orderWorks   同一订单工单集合
	 * @param refundAmount 订单已退款金额
	 * @author huangchao
	 */
	private void processOrderWarrantyCardStatusUpdate(OmsRefundRequestDTO refundRequestDTO, List<OrderWork> orderWorks, int refundAmount) {
		// 获取原单收入
		Integer totalAmount = orderWorks.stream().filter(orderWork -> Objects.equals(orderWork.getOrderId(), orderWork.getWorkId()))
				.mapToInt(OrderWork::getTotalAmount).findFirst().orElse(0);
		Integer remainingAmount = totalAmount - refundAmount;
		if (Objects.equals(0, remainingAmount) || remainingAmount <= ONLY_RUN_ORDER_AMOUNT) {
			List<OrderWarrantyProduct> warrantyProducts = orderWarrantyProductService.listByOrderId(refundRequestDTO.getOrderId());
			if (CollectionUtil.isNotNullOrEmpty(warrantyProducts)) {
				OrderWarrantyProduct warrantyProduct = new OrderWarrantyProduct();
				warrantyProduct.setExpiredTime(DateUtil.getNow());
				warrantyProduct.setWarrId(refundRequestDTO.getOrderId());
				orderWarrantyProductService.updateExpiredTime(warrantyProduct);
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_REFUND_DIFFERENCE, beforeProceed = false)
	public void refundDifference(RefundDifferenceDTO refundDifferenceDTO) throws OmsBaseException {
		/**
		 * 发起退款：
		 * 1.插入支付记录
		 * 2.修改订单支付状态为退款中
		 * 3.发起退款（夏敏接口）
		 */

		logger.info("订单退差额={}", refundDifferenceDTO);

		if (NumberUtil.isNullOrZero(refundDifferenceDTO.getRefundDifferenceAmount())) {
			return;
		}

		OrderWork orderWork = orderWorkService.findOrderWorkByKey(refundDifferenceDTO.getOrderId(), refundDifferenceDTO.getWorkId());
		// 非一口价订单不允许退差额
		if (!Objects.equals(orderWork.getFinalPrice(), GlobalConsts.YES)) {
			return;
		}

		// 校验差额金额
		Integer remainingReceivableAmount = orderAmountBService.getOrderWorkRemainingReceivableAmount(orderWork);
		if (0 != (remainingReceivableAmount + refundDifferenceDTO.getRefundDifferenceAmount())) {
			// 正数+负数=0
			throw new OmsBaseException(OrderFailConsts.FAIL_DATA_CHANGE_ORDER_DIFFERENCE, "退款金额有变化！");
		}


//		OrderPay refundPay = new OrderPay();
//		refundPay.setOrderId(orderWork.getOrderId());
//		refundPay.setWorkId(orderWork.getWorkId());
//		refundPay.setAmountType(0);
//		refundPay.setTradeType(PayConsts.PAY_TRADE_TYPE_REFUND);
//		refundPay.setRefundType(OrderConsts.ORDER_REFUND_TYPE_ONLINE);
//		refundPay.setPayStatus(PayConsts.REFUND_STATUS_ING);
//		refundPay.setAmount(refundDifferenceDTO.getRefundDifferenceAmount());
//		refundPay.setDuplicate(GlobalConsts.NO);
//		refundPay.setCreater(org.apache.commons.lang.StringUtils.defaultString(refundDifferenceDTO.getOperator(), "系统"));
//		refundPay.setUpdater(org.apache.commons.lang.StringUtils.defaultString(refundDifferenceDTO.getOperator(), "系统"));
//		refundPay.setCreateTime(DateUtil.getNow());
//		refundPay.setUpdateTime(DateUtil.getNow());
//		orderPayService.insertOrderPay(refundPay);

		OrderWork updateOrderWork = new OrderWork();
		updateOrderWork.setOrderId(refundDifferenceDTO.getOrderId());
		updateOrderWork.setWorkId(refundDifferenceDTO.getWorkId());
		updateOrderWork.setRefundAmount(refundDifferenceDTO.getRefundDifferenceAmount());
		updateOrderWork.setPayStatus(PayConsts.REFUND_STATUS_ING);
		updateOrderWork.setUpdateTime(DateUtil.getNow());
		orderWorkService.updateOrderWorkByKey(updateOrderWork);

		List<OrderPay> orderPayList = orderPayService.listOrderPayByOrderId(orderWork.getOrderId());
		RefundInitiateBO refundInitiateBO = RefundInitiateBO.builder()
				.refundInitiateType(RefundInitiateTypeEnum.REFUND_DIFFERENCE.getType())
				.refundType(OrderConsts.ORDER_REFUND_TYPE_ONLINE)
//				.orderPayId(refundPay.getOrderPayId())
				.refundAmount(refundDifferenceDTO.getRefundDifferenceAmount())
				.originalOrderId(orderWork.getOrderId())
				.originalOrderWorkBizType(orderWork.getBizType())
				.refundOrderWork(orderWork)
				.operator(refundDifferenceDTO)
				.orderPayList(orderPayList)
				.build();
		zsOrderPayBService.payRefundAmount(refundInitiateBO);
	}

	@Override
	public void differenceRefundCallback(RefundResultDRO refundResultDRO) {
		/**
		 * 退款回调：
		 *
		 * 2.预付款减去已退金额
		 * 3.修改订单支付状态为已支付
		 * 4.完成订单
		 */
		logger.info("差额退款结果通知==>{}", refundResultDRO);
		OmsRefundRequestDTO refundRequestDTO = JSON.parseObject(refundResultDRO.getRequestData(), OmsRefundRequestDTO.class);

		OrderWork orderWork = orderWorkService.findOrderWorkByKey(refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId());
		if (Objects.isNull(orderWork)) {
			logger.error("{} 订单不存在", refundRequestDTO.getWorkId());
			return;
		}
		if (orderWork.getPrepayAmount() < refundResultDRO.getRefundAmount()) {
			logger.error("{} 订单预付小于退款金额", refundRequestDTO.getWorkId());
			return;
		}

		if (!Objects.equals(orderWork.getPayStatus(), PayConsts.REFUND_STATUS_ING)) {
			logger.error("{} 订单不在退款中", refundRequestDTO.getWorkId());
		}

		if (orderWork.getStatus() >= OrderStatusConsts.WORK_STATUS_COMPLETE) {
			logger.error("{} 订单已完成", refundRequestDTO.getWorkId());
		}

		String lockKey = String.format("%s_%s_%s", refundRequestDTO.getOrderId(), refundRequestDTO.getWorkId(), PayConsts.PAY_TRADE_TYPE_REFUND);
		DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_REFUND_FORMAT + lockKey, LockConsts.LOCK_VALID_TIME);
		try {
			if (lock.tryLock()) {
				// 插入支付记录
				orderPayBService.insertRefundOrderPay(refundResultDRO, refundRequestDTO);

				// 修改订单
				WorkRefundResultDTO workRefundResultDto = this.getWorkRefundResultDto(refundResultDRO);
				orderWorkBAmountBService.updateRefundResult(workRefundResultDto);

				if (!Objects.equals(workRefundResultDto.getAllRefund(),GlobalConsts.YES)) {
					return;
				}
				// 完成订单
				// 更新完成
				CompleteDTO completeDTO = new CompleteDTO();
				completeDTO.setOrderId(orderWork.getOrderId());
				completeDTO.setWorkId(orderWork.getWorkId());
				completeDTO.setOperator("系统");
				completeDTO.setOperatorId(1L);
				completeDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
				try {
					zsNormalMasterWorkBService.completeOrder(completeDTO);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}

				workFlowContextBService.asyncAutoFlow(orderWork.getOrderId(), orderWork.getWorkId());
			}
		} catch (Exception e) {
			logger.error("订单退款异常:" + e.getMessage(), e);
		}finally {
			lock.unlock();
		}
	}

	/**
	 * 不支持原路退
	 *
	 * @param orderPays
	 */
	private NoBacktrackingAmountVO noBacktrackingAmount(List<OrderPay> orderPays) {
		List<OrderPay> payList = orderPays.stream().filter(orderPay -> !Objects.equals(orderPay.getTradeType(), PayConsts.PAY_TRADE_TYPE_REFUND) &&
				Objects.equals(orderPay.getPayStatus(), PayConsts.PAY_STATUS_DONE))
				.collect(Collectors.toList());
		if (CollectionUtil.isNullOrEmpty(payList)) {
			return NoBacktrackingAmountVO.builder().build();
		}
		// 渠道预付款
		int channelPrepayAmount = 0;
		// 工程师支付
		int engineerPayAmount = 0;
		// 对公转账
		int bankPayAmount = 0;
		for (OrderPay orderPay : orderPays) {
			if (Objects.equals(orderPay.getAmountType(), OrderPayConsts.ORDER_PAY_CHANNEL_PREPAY)) {
				channelPrepayAmount += orderPay.getAmount();
			} else if (Objects.equals(orderPay.getPayType(), PayConsts.PAY_TYPE_APP)) {
				engineerPayAmount += orderPay.getAmount();
			} else if (Objects.equals(orderPay.getPayChannelId(), PayConsts.PAY_CHANNEL_PLATFORM_BANKTRANSFER)) {
				bankPayAmount += orderPay.getAmount();
			}
		}
		return NoBacktrackingAmountVO.builder()
				.channelPrepayAmount(channelPrepayAmount)
				.engineerPayAmount(engineerPayAmount)
				.bankPayAmount(bankPayAmount)
				.build();
	}

	/**
	 * 退款失败或异常处理
	 *
	 * @param orderWork 工单信息
	 * @param content
	 */
	private void refundFailHandle(OrderWork orderWork, String content,String redisKey) {
		logger.info("refundFailOrderLog 退款失败日志，入参{}，入参2{}", JSON.toJSONString(orderWork), content);
		// 删除锁
		if (Objects.nonNull(redisKey) && redisManager.exists(redisKey)) {
			redisManager.del(redisKey);
		}
		// 插入退款失败日志
		OrderLog orderLog = new OrderLog();
		orderLog.setOrderId(orderWork.getOrderId());
		orderLog.setWorkId(orderWork.getWorkId());
		orderLog.setBeforeStatus(orderWork.getStatus());
		orderLog.setBeforeStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
		orderLog.setBeforeResultStatus(orderWork.getResultStatus());
		orderLog.setBeforeResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
		orderLog.setAfterStatus(orderLog.getBeforeStatus());
		orderLog.setAfterStatusName(orderLog.getBeforeStatusName());
		orderLog.setAfterResultStatus(orderLog.getBeforeResultStatus());
		orderLog.setAfterResultStatusName(orderLog.getBeforeResultStatusName());
		orderLog.setContent("由于" + (Objects.nonNull(content) ? content : " ") + "，导致退款异常，建议走人工退款");
		orderLog.setType(OrderLogConsts.ORDER_LOG_TYPE_REFUND_FAIL);
		orderLog.setTypeName(OrderLogConsts.getOrderLogTypeName(OrderLogConsts.ORDER_LOG_TYPE_REFUND_FAIL));
		orderLog.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
		orderLog.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
		orderLog.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
		orderLog.setOperatorTypeName(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
		orderLogBService.save(orderLog);
	}
}
